@abinashpatri/cache 1.0.0 → 1.0.1

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/README.md CHANGED
@@ -6,6 +6,7 @@ Built for simple integration with:
6
6
  - safe JSON serialization/deserialization
7
7
  - TTL with jitter to reduce cache stampedes
8
8
  - auto-cache wrapper (`remember`)
9
+ - Redis-backed Express rate limiting (`express-rate-limit` + Redis store)
9
10
  - ESM + CommonJS support
10
11
  - full TypeScript typings
11
12
 
@@ -123,12 +124,166 @@ const posts = await remember("posts:home", 30, async () => {
123
124
  });
124
125
  ```
125
126
 
127
+ ### `createRedisRateLimiter(options?): RateLimitRequestHandler`
128
+
129
+ Creates an Express middleware that stores rate-limit counters in Redis.
130
+
131
+ Defaults:
132
+ - `windowMs`: `15 * 60 * 1000` (15 minutes)
133
+ - `limit`: `100`
134
+ - `standardHeaders`: `"draft-7"`
135
+ - `legacyHeaders`: `false`
136
+ - Redis key `prefix`: `"rl:"`
137
+
138
+ ```ts
139
+ import express from "express";
140
+ import { connect, createRedisRateLimiter } from "@abinashpatri/cache";
141
+
142
+ const app = express();
143
+
144
+ await connect(process.env.REDIS_URL);
145
+
146
+ const limiter = createRedisRateLimiter({
147
+ windowMs: 15 * 60 * 1000,
148
+ limit: 100,
149
+ prefix: "rate-limit:",
150
+ message: {
151
+ success: false,
152
+ message: "Too many requests, please try again later.",
153
+ },
154
+ });
155
+
156
+ app.use("/api", limiter);
157
+
158
+ app.get("/api/health", (_req, res) => {
159
+ res.json({ ok: true });
160
+ });
161
+ ```
162
+
163
+ Important: call `connect()` before creating or using the limiter so Redis is ready.
164
+
165
+ ## Rate Limit Patterns (Express)
166
+
167
+ ### 1) Global limiter (all routes)
168
+
169
+ ```ts
170
+ const globalLimiter = createRedisRateLimiter({
171
+ windowMs: 15 * 60 * 1000,
172
+ limit: 300,
173
+ prefix: "rl:global:",
174
+ });
175
+
176
+ app.use(globalLimiter);
177
+ ```
178
+
179
+ ### 2) Router-level limiter (only `/api`)
180
+
181
+ ```ts
182
+ const apiLimiter = createRedisRateLimiter({
183
+ windowMs: 60 * 1000,
184
+ limit: 100,
185
+ prefix: "rl:api:",
186
+ });
187
+
188
+ app.use("/api", apiLimiter);
189
+ ```
190
+
191
+ ### 3) Route-level limiter (single endpoint)
192
+
193
+ ```ts
194
+ const loginLimiter = createRedisRateLimiter({
195
+ windowMs: 10 * 60 * 1000,
196
+ limit: 5,
197
+ prefix: "rl:login:",
198
+ });
199
+
200
+ app.post("/auth/login", loginLimiter, loginHandler);
201
+ ```
202
+
203
+ ### 4) Different limits for different routes
204
+
205
+ ```ts
206
+ const strictLimiter = createRedisRateLimiter({ windowMs: 60 * 1000, limit: 20, prefix: "rl:strict:" });
207
+ const relaxedLimiter = createRedisRateLimiter({ windowMs: 60 * 1000, limit: 200, prefix: "rl:relaxed:" });
208
+
209
+ app.use("/auth", strictLimiter);
210
+ app.use("/public", relaxedLimiter);
211
+ ```
212
+
213
+ ### 5) Per-user/API key rate limit (custom key generator)
214
+
215
+ ```ts
216
+ const userLimiter = createRedisRateLimiter({
217
+ windowMs: 60 * 1000,
218
+ limit: 60,
219
+ prefix: "rl:user:",
220
+ keyGenerator: (req) => {
221
+ const userId = req.headers["x-user-id"];
222
+ if (typeof userId === "string" && userId.length > 0) return `user:${userId}`;
223
+ return req.ip ?? "unknown";
224
+ },
225
+ });
226
+
227
+ app.use("/v1", userLimiter);
228
+ ```
229
+
230
+ ### 6) Skip successful requests (limit only failed attempts)
231
+
232
+ Useful for brute-force protection on auth endpoints.
233
+
234
+ ```ts
235
+ const authLimiter = createRedisRateLimiter({
236
+ windowMs: 15 * 60 * 1000,
237
+ limit: 10,
238
+ prefix: "rl:auth:",
239
+ skipSuccessfulRequests: true,
240
+ });
241
+
242
+ app.post("/auth/login", authLimiter, loginHandler);
243
+ ```
244
+
245
+ ### 7) Custom 429 response handler
246
+
247
+ ```ts
248
+ const customHandlerLimiter = createRedisRateLimiter({
249
+ windowMs: 60 * 1000,
250
+ limit: 50,
251
+ prefix: "rl:custom:",
252
+ handler: (req, res) => {
253
+ res.status(429).json({
254
+ success: false,
255
+ message: "Rate limit exceeded",
256
+ route: req.originalUrl,
257
+ });
258
+ },
259
+ });
260
+
261
+ app.use("/api", customHandlerLimiter);
262
+ ```
263
+
264
+ ### 8) Proxy/LB deployment setup (important)
265
+
266
+ ```ts
267
+ app.set("trust proxy", 1);
268
+ ```
269
+
270
+ Set this when running behind Nginx, Cloudflare, Render, Railway, Heroku, or similar proxy/CDN, so client IP based limiting is correct.
271
+
126
272
  ## Import Styles
127
273
 
128
274
  ### Named imports (recommended)
129
275
 
130
276
  ```ts
131
- import { connect, get, set, del, remember, ping, disconnect } from "@abinashpatri/cache";
277
+ import {
278
+ connect,
279
+ get,
280
+ set,
281
+ del,
282
+ remember,
283
+ ping,
284
+ disconnect,
285
+ createRedisRateLimiter,
286
+ } from "@abinashpatri/cache";
132
287
  ```
133
288
 
134
289
  ### Default import
@@ -138,6 +293,7 @@ import cache from "@abinashpatri/cache";
138
293
 
139
294
  await cache.connect();
140
295
  await cache.set("k", { ok: true }, 60);
296
+ const limiter = cache.createRedisRateLimiter({ limit: 50 });
141
297
  ```
142
298
 
143
299
  ## Production Usage Notes
package/dist/index.d.mts CHANGED
@@ -1,3 +1,11 @@
1
+ import { Options, RateLimitRequestHandler } from 'express-rate-limit';
2
+
3
+ type RedisRateLimitOptions = Partial<Omit<Options, "store">> & {
4
+ prefix?: string;
5
+ resetExpiryOnChange?: boolean;
6
+ };
7
+ declare function createRedisRateLimiter(options?: RedisRateLimitOptions): RateLimitRequestHandler;
8
+
1
9
  declare function get<T = unknown>(key: string): Promise<T | null>;
2
10
  declare function set<T>(key: string, value: T, ttl?: number): Promise<void>;
3
11
  declare function del(key: string): Promise<void>;
@@ -15,6 +23,7 @@ declare const redis: {
15
23
  connect: typeof connect;
16
24
  disconnect: typeof disconnect;
17
25
  ping: typeof ping;
26
+ createRedisRateLimiter: typeof createRedisRateLimiter;
18
27
  };
19
28
 
20
- export { connect, redis as default, del, disconnect, get, ping, remember, set };
29
+ export { type RedisRateLimitOptions, connect, createRedisRateLimiter, redis as default, del, disconnect, get, ping, remember, set };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ import { Options, RateLimitRequestHandler } from 'express-rate-limit';
2
+
3
+ type RedisRateLimitOptions = Partial<Omit<Options, "store">> & {
4
+ prefix?: string;
5
+ resetExpiryOnChange?: boolean;
6
+ };
7
+ declare function createRedisRateLimiter(options?: RedisRateLimitOptions): RateLimitRequestHandler;
8
+
1
9
  declare function get<T = unknown>(key: string): Promise<T | null>;
2
10
  declare function set<T>(key: string, value: T, ttl?: number): Promise<void>;
3
11
  declare function del(key: string): Promise<void>;
@@ -15,6 +23,7 @@ declare const redis: {
15
23
  connect: typeof connect;
16
24
  disconnect: typeof disconnect;
17
25
  ping: typeof ping;
26
+ createRedisRateLimiter: typeof createRedisRateLimiter;
18
27
  };
19
28
 
20
- export { connect, redis as default, del, disconnect, get, ping, remember, set };
29
+ export { type RedisRateLimitOptions, connect, createRedisRateLimiter, redis as default, del, disconnect, get, ping, remember, set };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var f=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var g=(n,t)=>{for(var e in t)f(n,e,{get:t[e],enumerable:!0})},b=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of R(t))!v.call(n,o)&&o!==e&&f(n,o,{get:()=>t[o],enumerable:!(i=P(t,o))||i.enumerable});return n};var J=n=>b(f({},"__esModule",{value:!0}),n);var M={};g(M,{connect:()=>C,default:()=>h,del:()=>m,disconnect:()=>y,get:()=>s,ping:()=>w,remember:()=>d,set:()=>l});module.exports=J(M);var T=require("redis"),r=null;async function x(n="redis://127.0.0.1:6379"){return r||(r=(0,T.createClient)({url:n}),r.on("connect",()=>{console.log("Redis connected")}),r.on("error",t=>{console.error("Redis error:",t)})),r.isOpen||await r.connect(),r}function c(){if(!r)throw new Error("Redis not connected. Call connect() first.");return r}var p={};g(p,{del:()=>m,get:()=>s,remember:()=>d,set:()=>l});function O(n){try{return JSON.parse(n)}catch{return null}}async function s(n){let e=await c().get(n);return e?O(e):null}async function l(n,t,e=60){let i=c(),o=e+Math.floor(Math.random()*10);await i.set(n,JSON.stringify(t),{EX:o})}async function m(n){await c().del(n)}async function d(n,t,e){let i=await s(n);if(i!==null)return console.log("Cache hit:",n),i;console.log("Cache miss:",n);let o=await e();return await l(n,o,t),o}var u=!1,a=null;async function C(n){if(!u)return a||(a=x(n).then(()=>{u=!0})),a}async function w(){return c().ping()}async function y(){if(!u)return;await c().quit(),u=!1,a=null}var E={connect:C,disconnect:y,ping:w,...p},h=E;0&&(module.exports={connect,del,disconnect,get,ping,remember,set});
1
+ "use strict";var H=Object.create;var a=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var R=(e,t)=>{for(var n in t)a(e,n,{get:t[n],enumerable:!0})},y=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of b(t))!E.call(e,r)&&r!==n&&a(e,r,{get:()=>t[r],enumerable:!(i=v(t,r))||i.enumerable});return e};var M=(e,t,n)=>(n=e!=null?H(q(e)):{},y(t||!e||!e.__esModule?a(n,"default",{value:e,enumerable:!0}):n,e)),J=e=>y(a({},"__esModule",{value:!0}),e);var W={};R(W,{connect:()=>P,createRedisRateLimiter:()=>m,default:()=>L,del:()=>f,disconnect:()=>O,get:()=>c,ping:()=>h,remember:()=>u,set:()=>l});module.exports=J(W);var x=require("redis"),o=null;async function C(e="redis://127.0.0.1:6379"){return o||(o=(0,x.createClient)({url:e}),o.on("connect",()=>{console.log("Redis connected")}),o.on("error",t=>{console.error("Redis error:",t)})),o.isOpen||await o.connect(),o}function s(){if(!o)throw new Error("Redis not connected. Call connect() first.");return o}var g={};R(g,{del:()=>f,get:()=>c,remember:()=>u,set:()=>l});function S(e){try{return JSON.parse(e)}catch{return null}}async function c(e){let n=await s().get(e);return n?S(n):null}async function l(e,t,n=60){let i=s(),r=n+Math.floor(Math.random()*10);await i.set(e,JSON.stringify(t),{EX:r})}async function f(e){await s().del(e)}async function u(e,t,n){let i=await c(e);if(i!==null)return console.log("Cache hit:",e),i;console.log("Cache miss:",e);let r=await n();return await l(e,r,t),r}var w=M(require("express-rate-limit")),T=require("rate-limit-redis");function m(e={}){let{prefix:t="rl:",resetExpiryOnChange:n=!1,...i}=e;return(0,w.default)({windowMs:i.windowMs??900*1e3,limit:i.limit??100,standardHeaders:i.standardHeaders??"draft-7",legacyHeaders:i.legacyHeaders??!1,message:i.message??"Too many requests, please try again later.",...i,store:new T.RedisStore({prefix:t,resetExpiryOnChange:n,sendCommand:(...r)=>s().sendCommand(r)})})}var p=!1,d=null;async function P(e){if(!p)return d||(d=C(e).then(()=>{p=!0})),d}async function h(){return s().ping()}async function O(){if(!p)return;await s().quit(),p=!1,d=null}var N={connect:P,disconnect:O,ping:h,createRedisRateLimiter:m,...g},L=N;0&&(module.exports={connect,createRedisRateLimiter,del,disconnect,get,ping,remember,set});
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/redis/connection.ts","../src/redis/cache.ts","../src/redis/index.ts"],"sourcesContent":["export * from \"./redis/index\";\nexport { default } from \"./redis/index\";\n","import { createClient, type RedisClientType } from \"redis\";\n\nlet client: RedisClientType | null = null;\n\nexport async function connect(url = \"redis://127.0.0.1:6379\"): Promise<RedisClientType> {\n if (!client) {\n client = createClient({ url });\n\n client.on(\"connect\", () => {\n console.log(\"Redis connected\");\n });\n\n client.on(\"error\", (err: unknown) => {\n console.error(\"Redis error:\", err);\n });\n }\n\n if (!client.isOpen) {\n await client.connect();\n }\n\n return client;\n}\n\nexport function getClient(): RedisClientType {\n if (!client) {\n throw new Error(\"Redis not connected. Call connect() first.\");\n }\n\n return client;\n}\n","import { getClient } from \"./connection\";\n\nfunction safeParse<T>(data: string): T | null {\n try {\n return JSON.parse(data) as T;\n } catch {\n return null;\n }\n}\n\nexport async function get<T = unknown>(key: string): Promise<T | null> {\n const client = getClient();\n const data = await client.get(key);\n\n return data ? safeParse<T>(data) : null;\n}\n\nexport async function set<T>(key: string, value: T, ttl = 60): Promise<void> {\n const client = getClient();\n const ttlWithJitter = ttl + Math.floor(Math.random() * 10);\n\n await client.set(key, JSON.stringify(value), {\n EX: ttlWithJitter,\n });\n}\n\nexport async function del(key: string): Promise<void> {\n const client = getClient();\n await client.del(key);\n}\n\nexport async function remember<T>(key: string, ttl: number, fn: () => Promise<T>): Promise<T> {\n const cached = await get<T>(key);\n\n if (cached !== null) {\n console.log(\"Cache hit:\", key);\n return cached;\n }\n\n console.log(\"Cache miss:\", key);\n\n const result = await fn();\n await set(key, result, ttl);\n\n return result;\n}\n","import { connect as connectClient, getClient } from \"./connection\";\nimport * as cache from \"./cache\";\n\nlet isConnected = false;\nlet connecting: Promise<void> | null = null;\n\nexport async function connect(url?: string): Promise<void> {\n if (isConnected) {\n return;\n }\n\n if (!connecting) {\n connecting = connectClient(url).then(() => {\n isConnected = true;\n });\n }\n\n return connecting;\n}\n\nexport async function ping(): Promise<string> {\n const client = getClient();\n return client.ping();\n}\n\nexport async function disconnect(): Promise<void> {\n if (!isConnected) {\n return;\n }\n\n const client = getClient();\n await client.quit();\n\n isConnected = false;\n connecting = null;\n}\n\nexport { get, set, del, remember } from \"./cache\";\n\nconst redis = {\n connect,\n disconnect,\n ping,\n ...cache,\n};\n\nexport default redis;\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,EAAA,QAAAC,EAAA,eAAAC,EAAA,QAAAC,EAAA,SAAAC,EAAA,aAAAC,EAAA,QAAAC,IAAA,eAAAC,EAAAV,GCAA,IAAAW,EAAmD,iBAE/CC,EAAiC,KAErC,eAAsBC,EAAQC,EAAM,yBAAoD,CACtF,OAAKF,IACHA,KAAS,gBAAa,CAAE,IAAAE,CAAI,CAAC,EAE7BF,EAAO,GAAG,UAAW,IAAM,CACzB,QAAQ,IAAI,iBAAiB,CAC/B,CAAC,EAEDA,EAAO,GAAG,QAAUG,GAAiB,CACnC,QAAQ,MAAM,eAAgBA,CAAG,CACnC,CAAC,GAGEH,EAAO,QACV,MAAMA,EAAO,QAAQ,EAGhBA,CACT,CAEO,SAASI,GAA6B,CAC3C,GAAI,CAACJ,EACH,MAAM,IAAI,MAAM,4CAA4C,EAG9D,OAAOA,CACT,CC9BA,IAAAK,EAAA,GAAAC,EAAAD,EAAA,SAAAE,EAAA,QAAAC,EAAA,aAAAC,EAAA,QAAAC,IAEA,SAASC,EAAaC,EAAwB,CAC5C,GAAI,CACF,OAAO,KAAK,MAAMA,CAAI,CACxB,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAsBC,EAAiBC,EAAgC,CAErE,IAAMF,EAAO,MADEG,EAAU,EACC,IAAID,CAAG,EAEjC,OAAOF,EAAOD,EAAaC,CAAI,EAAI,IACrC,CAEA,eAAsBI,EAAOF,EAAaG,EAAUC,EAAM,GAAmB,CAC3E,IAAMC,EAASJ,EAAU,EACnBK,EAAgBF,EAAM,KAAK,MAAM,KAAK,OAAO,EAAI,EAAE,EAEzD,MAAMC,EAAO,IAAIL,EAAK,KAAK,UAAUG,CAAK,EAAG,CAC3C,GAAIG,CACN,CAAC,CACH,CAEA,eAAsBC,EAAIP,EAA4B,CAEpD,MADeC,EAAU,EACZ,IAAID,CAAG,CACtB,CAEA,eAAsBQ,EAAYR,EAAaI,EAAaK,EAAkC,CAC5F,IAAMC,EAAS,MAAMX,EAAOC,CAAG,EAE/B,GAAIU,IAAW,KACb,eAAQ,IAAI,aAAcV,CAAG,EACtBU,EAGT,QAAQ,IAAI,cAAeV,CAAG,EAE9B,IAAMW,EAAS,MAAMF,EAAG,EACxB,aAAMP,EAAIF,EAAKW,EAAQP,CAAG,EAEnBO,CACT,CC1CA,IAAIC,EAAc,GACdC,EAAmC,KAEvC,eAAsBC,EAAQC,EAA6B,CACzD,GAAI,CAAAH,EAIJ,OAAKC,IACHA,EAAaC,EAAcC,CAAG,EAAE,KAAK,IAAM,CACzCH,EAAc,EAChB,CAAC,GAGIC,CACT,CAEA,eAAsBG,GAAwB,CAE5C,OADeC,EAAU,EACX,KAAK,CACrB,CAEA,eAAsBC,GAA4B,CAChD,GAAI,CAACN,EACH,OAIF,MADeK,EAAU,EACZ,KAAK,EAElBL,EAAc,GACdC,EAAa,IACf,CAIA,IAAMM,EAAQ,CACZ,QAAAL,EACA,WAAAI,EACA,KAAAF,EACA,GAAGI,CACL,EAEOC,EAAQF","names":["index_exports","__export","connect","redis_default","del","disconnect","get","ping","remember","set","__toCommonJS","import_redis","client","connect","url","err","getClient","cache_exports","__export","del","get","remember","set","safeParse","data","get","key","getClient","set","value","ttl","client","ttlWithJitter","del","remember","fn","cached","result","isConnected","connecting","connect","url","ping","getClient","disconnect","redis","cache_exports","redis_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/redis/connection.ts","../src/redis/cache.ts","../src/rate-limit.ts","../src/redis/index.ts"],"sourcesContent":["export * from \"./redis/index\";\nexport { default } from \"./redis/index\";\nexport * from \"./rate-limit\";\n","import { createClient, type RedisClientType } from \"redis\";\n\nlet client: RedisClientType | null = null;\n\nexport async function connect(url = \"redis://127.0.0.1:6379\"): Promise<RedisClientType> {\n if (!client) {\n client = createClient({ url });\n\n client.on(\"connect\", () => {\n console.log(\"Redis connected\");\n });\n\n client.on(\"error\", (err: unknown) => {\n console.error(\"Redis error:\", err);\n });\n }\n\n if (!client.isOpen) {\n await client.connect();\n }\n\n return client;\n}\n\nexport function getClient(): RedisClientType {\n if (!client) {\n throw new Error(\"Redis not connected. Call connect() first.\");\n }\n\n return client;\n}\n","import { getClient } from \"./connection\";\n\nfunction safeParse<T>(data: string): T | null {\n try {\n return JSON.parse(data) as T;\n } catch {\n return null;\n }\n}\n\nexport async function get<T = unknown>(key: string): Promise<T | null> {\n const client = getClient();\n const data = await client.get(key);\n\n return data ? safeParse<T>(data) : null;\n}\n\nexport async function set<T>(key: string, value: T, ttl = 60): Promise<void> {\n const client = getClient();\n const ttlWithJitter = ttl + Math.floor(Math.random() * 10);\n\n await client.set(key, JSON.stringify(value), {\n EX: ttlWithJitter,\n });\n}\n\nexport async function del(key: string): Promise<void> {\n const client = getClient();\n await client.del(key);\n}\n\nexport async function remember<T>(key: string, ttl: number, fn: () => Promise<T>): Promise<T> {\n const cached = await get<T>(key);\n\n if (cached !== null) {\n console.log(\"Cache hit:\", key);\n return cached;\n }\n\n console.log(\"Cache miss:\", key);\n\n const result = await fn();\n await set(key, result, ttl);\n\n return result;\n}\n","import rateLimit, { type Options, type RateLimitRequestHandler } from \"express-rate-limit\";\nimport { RedisStore, type RedisReply } from \"rate-limit-redis\";\nimport { getClient } from \"./redis/connection\";\n\nexport type RedisRateLimitOptions = Partial<Omit<Options, \"store\">> & {\n prefix?: string;\n resetExpiryOnChange?: boolean;\n};\n\nexport function createRedisRateLimiter(options: RedisRateLimitOptions = {}): RateLimitRequestHandler {\n const { prefix = \"rl:\", resetExpiryOnChange = false, ...rateLimitOptions } = options;\n\n return rateLimit({\n windowMs: rateLimitOptions.windowMs ?? 15 * 60 * 1000,\n limit: rateLimitOptions.limit ?? 100,\n standardHeaders: rateLimitOptions.standardHeaders ?? \"draft-7\",\n legacyHeaders: rateLimitOptions.legacyHeaders ?? false,\n message: rateLimitOptions.message ?? \"Too many requests, please try again later.\",\n ...rateLimitOptions,\n store: new RedisStore({\n prefix,\n resetExpiryOnChange,\n sendCommand: (...args: string[]): Promise<RedisReply> =>\n getClient().sendCommand(args) as Promise<RedisReply>,\n }),\n });\n}\n","import { connect as connectClient, getClient } from \"./connection\";\nimport * as cache from \"./cache\";\nimport { createRedisRateLimiter } from \"../rate-limit\";\n\nlet isConnected = false;\nlet connecting: Promise<void> | null = null;\n\nexport async function connect(url?: string): Promise<void> {\n if (isConnected) {\n return;\n }\n\n if (!connecting) {\n connecting = connectClient(url).then(() => {\n isConnected = true;\n });\n }\n\n return connecting;\n}\n\nexport async function ping(): Promise<string> {\n const client = getClient();\n return client.ping();\n}\n\nexport async function disconnect(): Promise<void> {\n if (!isConnected) {\n return;\n }\n\n const client = getClient();\n await client.quit();\n\n isConnected = false;\n connecting = null;\n}\n\nexport { get, set, del, remember } from \"./cache\";\nexport { createRedisRateLimiter } from \"../rate-limit\";\n\nconst redis = {\n connect,\n disconnect,\n ping,\n createRedisRateLimiter,\n ...cache,\n};\n\nexport default redis;\n"],"mappings":"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","names":["index_exports","__export","connect","createRedisRateLimiter","redis_default","del","disconnect","get","ping","remember","set","__toCommonJS","import_redis","client","connect","url","err","getClient","cache_exports","__export","del","get","remember","set","safeParse","data","get","key","getClient","set","value","ttl","client","ttlWithJitter","del","remember","fn","cached","result","import_express_rate_limit","import_rate_limit_redis","createRedisRateLimiter","options","prefix","resetExpiryOnChange","rateLimitOptions","rateLimit","args","getClient","isConnected","connecting","connect","url","ping","getClient","disconnect","redis","createRedisRateLimiter","cache_exports","redis_default"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var g=Object.defineProperty;var T=(n,t)=>{for(var e in t)g(n,e,{get:t[e],enumerable:!0})};import{createClient as x}from"redis";var o=null;async function m(n="redis://127.0.0.1:6379"){return o||(o=x({url:n}),o.on("connect",()=>{console.log("Redis connected")}),o.on("error",t=>{console.error("Redis error:",t)})),o.isOpen||await o.connect(),o}function r(){if(!o)throw new Error("Redis not connected. Call connect() first.");return o}var f={};T(f,{del:()=>d,get:()=>a,remember:()=>p,set:()=>u});function C(n){try{return JSON.parse(n)}catch{return null}}async function a(n){let e=await r().get(n);return e?C(e):null}async function u(n,t,e=60){let i=r(),c=e+Math.floor(Math.random()*10);await i.set(n,JSON.stringify(t),{EX:c})}async function d(n){await r().del(n)}async function p(n,t,e){let i=await a(n);if(i!==null)return console.log("Cache hit:",n),i;console.log("Cache miss:",n);let c=await e();return await u(n,c,t),c}var l=!1,s=null;async function w(n){if(!l)return s||(s=m(n).then(()=>{l=!0})),s}async function y(){return r().ping()}async function h(){if(!l)return;await r().quit(),l=!1,s=null}var P={connect:w,disconnect:h,ping:y,...f},R=P;export{w as connect,R as default,d as del,h as disconnect,a as get,y as ping,p as remember,u as set};
1
+ var R=Object.defineProperty;var y=(e,t)=>{for(var n in t)R(e,n,{get:t[n],enumerable:!0})};import{createClient as x}from"redis";var r=null;async function f(e="redis://127.0.0.1:6379"){return r||(r=x({url:e}),r.on("connect",()=>{console.log("Redis connected")}),r.on("error",t=>{console.error("Redis error:",t)})),r.isOpen||await r.connect(),r}function o(){if(!r)throw new Error("Redis not connected. Call connect() first.");return r}var d={};y(d,{del:()=>u,get:()=>l,remember:()=>g,set:()=>m});function C(e){try{return JSON.parse(e)}catch{return null}}async function l(e){let n=await o().get(e);return n?C(n):null}async function m(e,t,n=60){let i=o(),s=n+Math.floor(Math.random()*10);await i.set(e,JSON.stringify(t),{EX:s})}async function u(e){await o().del(e)}async function g(e,t,n){let i=await l(e);if(i!==null)return console.log("Cache hit:",e),i;console.log("Cache miss:",e);let s=await n();return await m(e,s,t),s}import w from"express-rate-limit";import{RedisStore as T}from"rate-limit-redis";function p(e={}){let{prefix:t="rl:",resetExpiryOnChange:n=!1,...i}=e;return w({windowMs:i.windowMs??900*1e3,limit:i.limit??100,standardHeaders:i.standardHeaders??"draft-7",legacyHeaders:i.legacyHeaders??!1,message:i.message??"Too many requests, please try again later.",...i,store:new T({prefix:t,resetExpiryOnChange:n,sendCommand:(...s)=>o().sendCommand(s)})})}var c=!1,a=null;async function P(e){if(!c)return a||(a=f(e).then(()=>{c=!0})),a}async function h(){return o().ping()}async function O(){if(!c)return;await o().quit(),c=!1,a=null}var L={connect:P,disconnect:O,ping:h,createRedisRateLimiter:p,...d},H=L;export{P as connect,p as createRedisRateLimiter,H as default,u as del,O as disconnect,l as get,h as ping,g as remember,m as set};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/redis/connection.ts","../src/redis/cache.ts","../src/redis/index.ts"],"sourcesContent":["import { createClient, type RedisClientType } from \"redis\";\n\nlet client: RedisClientType | null = null;\n\nexport async function connect(url = \"redis://127.0.0.1:6379\"): Promise<RedisClientType> {\n if (!client) {\n client = createClient({ url });\n\n client.on(\"connect\", () => {\n console.log(\"Redis connected\");\n });\n\n client.on(\"error\", (err: unknown) => {\n console.error(\"Redis error:\", err);\n });\n }\n\n if (!client.isOpen) {\n await client.connect();\n }\n\n return client;\n}\n\nexport function getClient(): RedisClientType {\n if (!client) {\n throw new Error(\"Redis not connected. Call connect() first.\");\n }\n\n return client;\n}\n","import { getClient } from \"./connection\";\n\nfunction safeParse<T>(data: string): T | null {\n try {\n return JSON.parse(data) as T;\n } catch {\n return null;\n }\n}\n\nexport async function get<T = unknown>(key: string): Promise<T | null> {\n const client = getClient();\n const data = await client.get(key);\n\n return data ? safeParse<T>(data) : null;\n}\n\nexport async function set<T>(key: string, value: T, ttl = 60): Promise<void> {\n const client = getClient();\n const ttlWithJitter = ttl + Math.floor(Math.random() * 10);\n\n await client.set(key, JSON.stringify(value), {\n EX: ttlWithJitter,\n });\n}\n\nexport async function del(key: string): Promise<void> {\n const client = getClient();\n await client.del(key);\n}\n\nexport async function remember<T>(key: string, ttl: number, fn: () => Promise<T>): Promise<T> {\n const cached = await get<T>(key);\n\n if (cached !== null) {\n console.log(\"Cache hit:\", key);\n return cached;\n }\n\n console.log(\"Cache miss:\", key);\n\n const result = await fn();\n await set(key, result, ttl);\n\n return result;\n}\n","import { connect as connectClient, getClient } from \"./connection\";\nimport * as cache from \"./cache\";\n\nlet isConnected = false;\nlet connecting: Promise<void> | null = null;\n\nexport async function connect(url?: string): Promise<void> {\n if (isConnected) {\n return;\n }\n\n if (!connecting) {\n connecting = connectClient(url).then(() => {\n isConnected = true;\n });\n }\n\n return connecting;\n}\n\nexport async function ping(): Promise<string> {\n const client = getClient();\n return client.ping();\n}\n\nexport async function disconnect(): Promise<void> {\n if (!isConnected) {\n return;\n }\n\n const client = getClient();\n await client.quit();\n\n isConnected = false;\n connecting = null;\n}\n\nexport { get, set, del, remember } from \"./cache\";\n\nconst redis = {\n connect,\n disconnect,\n ping,\n ...cache,\n};\n\nexport default redis;\n"],"mappings":"0FAAA,OAAS,gBAAAA,MAA0C,QAEnD,IAAIC,EAAiC,KAErC,eAAsBC,EAAQC,EAAM,yBAAoD,CACtF,OAAKF,IACHA,EAASD,EAAa,CAAE,IAAAG,CAAI,CAAC,EAE7BF,EAAO,GAAG,UAAW,IAAM,CACzB,QAAQ,IAAI,iBAAiB,CAC/B,CAAC,EAEDA,EAAO,GAAG,QAAUG,GAAiB,CACnC,QAAQ,MAAM,eAAgBA,CAAG,CACnC,CAAC,GAGEH,EAAO,QACV,MAAMA,EAAO,QAAQ,EAGhBA,CACT,CAEO,SAASI,GAA6B,CAC3C,GAAI,CAACJ,EACH,MAAM,IAAI,MAAM,4CAA4C,EAG9D,OAAOA,CACT,CC9BA,IAAAK,EAAA,GAAAC,EAAAD,EAAA,SAAAE,EAAA,QAAAC,EAAA,aAAAC,EAAA,QAAAC,IAEA,SAASC,EAAaC,EAAwB,CAC5C,GAAI,CACF,OAAO,KAAK,MAAMA,CAAI,CACxB,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAsBC,EAAiBC,EAAgC,CAErE,IAAMF,EAAO,MADEG,EAAU,EACC,IAAID,CAAG,EAEjC,OAAOF,EAAOD,EAAaC,CAAI,EAAI,IACrC,CAEA,eAAsBI,EAAOF,EAAaG,EAAUC,EAAM,GAAmB,CAC3E,IAAMC,EAASJ,EAAU,EACnBK,EAAgBF,EAAM,KAAK,MAAM,KAAK,OAAO,EAAI,EAAE,EAEzD,MAAMC,EAAO,IAAIL,EAAK,KAAK,UAAUG,CAAK,EAAG,CAC3C,GAAIG,CACN,CAAC,CACH,CAEA,eAAsBC,EAAIP,EAA4B,CAEpD,MADeC,EAAU,EACZ,IAAID,CAAG,CACtB,CAEA,eAAsBQ,EAAYR,EAAaI,EAAaK,EAAkC,CAC5F,IAAMC,EAAS,MAAMX,EAAOC,CAAG,EAE/B,GAAIU,IAAW,KACb,eAAQ,IAAI,aAAcV,CAAG,EACtBU,EAGT,QAAQ,IAAI,cAAeV,CAAG,EAE9B,IAAMW,EAAS,MAAMF,EAAG,EACxB,aAAMP,EAAIF,EAAKW,EAAQP,CAAG,EAEnBO,CACT,CC1CA,IAAIC,EAAc,GACdC,EAAmC,KAEvC,eAAsBC,EAAQC,EAA6B,CACzD,GAAI,CAAAH,EAIJ,OAAKC,IACHA,EAAaC,EAAcC,CAAG,EAAE,KAAK,IAAM,CACzCH,EAAc,EAChB,CAAC,GAGIC,CACT,CAEA,eAAsBG,GAAwB,CAE5C,OADeC,EAAU,EACX,KAAK,CACrB,CAEA,eAAsBC,GAA4B,CAChD,GAAI,CAACN,EACH,OAIF,MADeK,EAAU,EACZ,KAAK,EAElBL,EAAc,GACdC,EAAa,IACf,CAIA,IAAMM,EAAQ,CACZ,QAAAL,EACA,WAAAI,EACA,KAAAF,EACA,GAAGI,CACL,EAEOC,EAAQF","names":["createClient","client","connect","url","err","getClient","cache_exports","__export","del","get","remember","set","safeParse","data","get","key","getClient","set","value","ttl","client","ttlWithJitter","del","remember","fn","cached","result","isConnected","connecting","connect","url","ping","getClient","disconnect","redis","cache_exports","redis_default"]}
1
+ {"version":3,"sources":["../src/redis/connection.ts","../src/redis/cache.ts","../src/rate-limit.ts","../src/redis/index.ts"],"sourcesContent":["import { createClient, type RedisClientType } from \"redis\";\n\nlet client: RedisClientType | null = null;\n\nexport async function connect(url = \"redis://127.0.0.1:6379\"): Promise<RedisClientType> {\n if (!client) {\n client = createClient({ url });\n\n client.on(\"connect\", () => {\n console.log(\"Redis connected\");\n });\n\n client.on(\"error\", (err: unknown) => {\n console.error(\"Redis error:\", err);\n });\n }\n\n if (!client.isOpen) {\n await client.connect();\n }\n\n return client;\n}\n\nexport function getClient(): RedisClientType {\n if (!client) {\n throw new Error(\"Redis not connected. Call connect() first.\");\n }\n\n return client;\n}\n","import { getClient } from \"./connection\";\n\nfunction safeParse<T>(data: string): T | null {\n try {\n return JSON.parse(data) as T;\n } catch {\n return null;\n }\n}\n\nexport async function get<T = unknown>(key: string): Promise<T | null> {\n const client = getClient();\n const data = await client.get(key);\n\n return data ? safeParse<T>(data) : null;\n}\n\nexport async function set<T>(key: string, value: T, ttl = 60): Promise<void> {\n const client = getClient();\n const ttlWithJitter = ttl + Math.floor(Math.random() * 10);\n\n await client.set(key, JSON.stringify(value), {\n EX: ttlWithJitter,\n });\n}\n\nexport async function del(key: string): Promise<void> {\n const client = getClient();\n await client.del(key);\n}\n\nexport async function remember<T>(key: string, ttl: number, fn: () => Promise<T>): Promise<T> {\n const cached = await get<T>(key);\n\n if (cached !== null) {\n console.log(\"Cache hit:\", key);\n return cached;\n }\n\n console.log(\"Cache miss:\", key);\n\n const result = await fn();\n await set(key, result, ttl);\n\n return result;\n}\n","import rateLimit, { type Options, type RateLimitRequestHandler } from \"express-rate-limit\";\nimport { RedisStore, type RedisReply } from \"rate-limit-redis\";\nimport { getClient } from \"./redis/connection\";\n\nexport type RedisRateLimitOptions = Partial<Omit<Options, \"store\">> & {\n prefix?: string;\n resetExpiryOnChange?: boolean;\n};\n\nexport function createRedisRateLimiter(options: RedisRateLimitOptions = {}): RateLimitRequestHandler {\n const { prefix = \"rl:\", resetExpiryOnChange = false, ...rateLimitOptions } = options;\n\n return rateLimit({\n windowMs: rateLimitOptions.windowMs ?? 15 * 60 * 1000,\n limit: rateLimitOptions.limit ?? 100,\n standardHeaders: rateLimitOptions.standardHeaders ?? \"draft-7\",\n legacyHeaders: rateLimitOptions.legacyHeaders ?? false,\n message: rateLimitOptions.message ?? \"Too many requests, please try again later.\",\n ...rateLimitOptions,\n store: new RedisStore({\n prefix,\n resetExpiryOnChange,\n sendCommand: (...args: string[]): Promise<RedisReply> =>\n getClient().sendCommand(args) as Promise<RedisReply>,\n }),\n });\n}\n","import { connect as connectClient, getClient } from \"./connection\";\nimport * as cache from \"./cache\";\nimport { createRedisRateLimiter } from \"../rate-limit\";\n\nlet isConnected = false;\nlet connecting: Promise<void> | null = null;\n\nexport async function connect(url?: string): Promise<void> {\n if (isConnected) {\n return;\n }\n\n if (!connecting) {\n connecting = connectClient(url).then(() => {\n isConnected = true;\n });\n }\n\n return connecting;\n}\n\nexport async function ping(): Promise<string> {\n const client = getClient();\n return client.ping();\n}\n\nexport async function disconnect(): Promise<void> {\n if (!isConnected) {\n return;\n }\n\n const client = getClient();\n await client.quit();\n\n isConnected = false;\n connecting = null;\n}\n\nexport { get, set, del, remember } from \"./cache\";\nexport { createRedisRateLimiter } from \"../rate-limit\";\n\nconst redis = {\n connect,\n disconnect,\n ping,\n createRedisRateLimiter,\n ...cache,\n};\n\nexport default redis;\n"],"mappings":"0FAAA,OAAS,gBAAAA,MAA0C,QAEnD,IAAIC,EAAiC,KAErC,eAAsBC,EAAQC,EAAM,yBAAoD,CACtF,OAAKF,IACHA,EAASD,EAAa,CAAE,IAAAG,CAAI,CAAC,EAE7BF,EAAO,GAAG,UAAW,IAAM,CACzB,QAAQ,IAAI,iBAAiB,CAC/B,CAAC,EAEDA,EAAO,GAAG,QAAUG,GAAiB,CACnC,QAAQ,MAAM,eAAgBA,CAAG,CACnC,CAAC,GAGEH,EAAO,QACV,MAAMA,EAAO,QAAQ,EAGhBA,CACT,CAEO,SAASI,GAA6B,CAC3C,GAAI,CAACJ,EACH,MAAM,IAAI,MAAM,4CAA4C,EAG9D,OAAOA,CACT,CC9BA,IAAAK,EAAA,GAAAC,EAAAD,EAAA,SAAAE,EAAA,QAAAC,EAAA,aAAAC,EAAA,QAAAC,IAEA,SAASC,EAAaC,EAAwB,CAC5C,GAAI,CACF,OAAO,KAAK,MAAMA,CAAI,CACxB,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAsBC,EAAiBC,EAAgC,CAErE,IAAMF,EAAO,MADEG,EAAU,EACC,IAAID,CAAG,EAEjC,OAAOF,EAAOD,EAAaC,CAAI,EAAI,IACrC,CAEA,eAAsBI,EAAOF,EAAaG,EAAUC,EAAM,GAAmB,CAC3E,IAAMC,EAASJ,EAAU,EACnBK,EAAgBF,EAAM,KAAK,MAAM,KAAK,OAAO,EAAI,EAAE,EAEzD,MAAMC,EAAO,IAAIL,EAAK,KAAK,UAAUG,CAAK,EAAG,CAC3C,GAAIG,CACN,CAAC,CACH,CAEA,eAAsBC,EAAIP,EAA4B,CAEpD,MADeC,EAAU,EACZ,IAAID,CAAG,CACtB,CAEA,eAAsBQ,EAAYR,EAAaI,EAAaK,EAAkC,CAC5F,IAAMC,EAAS,MAAMX,EAAOC,CAAG,EAE/B,GAAIU,IAAW,KACb,eAAQ,IAAI,aAAcV,CAAG,EACtBU,EAGT,QAAQ,IAAI,cAAeV,CAAG,EAE9B,IAAMW,EAAS,MAAMF,EAAG,EACxB,aAAMP,EAAIF,EAAKW,EAAQP,CAAG,EAEnBO,CACT,CC7CA,OAAOC,MAA+D,qBACtE,OAAS,cAAAC,MAAmC,mBAQrC,SAASC,EAAuBC,EAAiC,CAAC,EAA4B,CACnG,GAAM,CAAE,OAAAC,EAAS,MAAO,oBAAAC,EAAsB,GAAO,GAAGC,CAAiB,EAAIH,EAE7E,OAAOI,EAAU,CACf,SAAUD,EAAiB,UAAY,IAAU,IACjD,MAAOA,EAAiB,OAAS,IACjC,gBAAiBA,EAAiB,iBAAmB,UACrD,cAAeA,EAAiB,eAAiB,GACjD,QAASA,EAAiB,SAAW,6CACrC,GAAGA,EACH,MAAO,IAAIE,EAAW,CACpB,OAAAJ,EACA,oBAAAC,EACA,YAAa,IAAII,IACfC,EAAU,EAAE,YAAYD,CAAI,CAChC,CAAC,CACH,CAAC,CACH,CCtBA,IAAIE,EAAc,GACdC,EAAmC,KAEvC,eAAsBC,EAAQC,EAA6B,CACzD,GAAI,CAAAH,EAIJ,OAAKC,IACHA,EAAaC,EAAcC,CAAG,EAAE,KAAK,IAAM,CACzCH,EAAc,EAChB,CAAC,GAGIC,CACT,CAEA,eAAsBG,GAAwB,CAE5C,OADeC,EAAU,EACX,KAAK,CACrB,CAEA,eAAsBC,GAA4B,CAChD,GAAI,CAACN,EACH,OAIF,MADeK,EAAU,EACZ,KAAK,EAElBL,EAAc,GACdC,EAAa,IACf,CAKA,IAAMM,EAAQ,CACZ,QAAAL,EACA,WAAAI,EACA,KAAAF,EACA,uBAAAI,EACA,GAAGC,CACL,EAEOC,EAAQH","names":["createClient","client","connect","url","err","getClient","cache_exports","__export","del","get","remember","set","safeParse","data","get","key","getClient","set","value","ttl","client","ttlWithJitter","del","remember","fn","cached","result","rateLimit","RedisStore","createRedisRateLimiter","options","prefix","resetExpiryOnChange","rateLimitOptions","rateLimit","RedisStore","args","getClient","isConnected","connecting","connect","url","ping","getClient","disconnect","redis","createRedisRateLimiter","cache_exports","redis_default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abinashpatri/cache",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Production-grade cache & rate limit utility library",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -37,6 +37,8 @@
37
37
  "typescript": "^5.9.3"
38
38
  },
39
39
  "dependencies": {
40
+ "express-rate-limit": "^8.3.1",
41
+ "rate-limit-redis": "^4.3.1",
40
42
  "redis": "^5.11.0"
41
43
  }
42
44
  }