@ooneex/cache 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ooneex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @ooneex/cache
@@ -0,0 +1,98 @@
1
+ import { Exception } from "@ooneex/exception";
2
+ declare class CacheException extends Exception {
3
+ constructor(message: string, data?: Record<string, unknown>);
4
+ }
5
+ type CacheClassType = new (...args: any[]) => ICache;
6
+ type RedisCacheAdapterType = {
7
+ connectionString?: string;
8
+ connectionTimeout?: number;
9
+ idleTimeout?: number;
10
+ autoReconnect?: boolean;
11
+ maxRetries?: number;
12
+ enableOfflineQueue?: boolean;
13
+ enableAutoPipelining?: boolean;
14
+ tls?: boolean | object;
15
+ };
16
+ type FilesystemCacheAdapterType = {
17
+ cacheDir?: string;
18
+ maxFileSize?: number;
19
+ cleanupInterval?: number;
20
+ enableCleanup?: boolean;
21
+ };
22
+ interface ICache {
23
+ get: <T = unknown>(key: string) => Promise<T | undefined>;
24
+ set: <T = unknown>(key: string, value: T, ttl?: number) => Promise<void>;
25
+ delete: (key: string) => Promise<boolean>;
26
+ has: (key: string) => Promise<boolean>;
27
+ mget: <T = unknown>(keys: string[]) => Promise<(T | undefined)[]>;
28
+ mset: <T = unknown>(entries: {
29
+ key: string;
30
+ value: T;
31
+ ttl?: number;
32
+ }[]) => Promise<void>;
33
+ ttl: (key: string) => Promise<number | null>;
34
+ expire: (key: string, ttl: number) => Promise<boolean>;
35
+ incr: (key: string, delta?: number) => Promise<number>;
36
+ decr: (key: string, delta?: number) => Promise<number>;
37
+ keys: (pattern?: string) => Promise<string[]>;
38
+ flush: () => Promise<void>;
39
+ }
40
+ declare class FilesystemCache implements ICache {
41
+ private cacheDir;
42
+ private maxFileSize;
43
+ private cleanupInterval;
44
+ private enableCleanup;
45
+ private cleanupTimer;
46
+ constructor(options?: FilesystemCacheAdapterType);
47
+ connect(): Promise<void>;
48
+ close(): Promise<void>;
49
+ get: <T = unknown>(key: string) => Promise<T | undefined>;
50
+ set: <T = unknown>(key: string, value: T, ttl?: number) => Promise<void>;
51
+ delete: (key: string) => Promise<boolean>;
52
+ has: (key: string) => Promise<boolean>;
53
+ mget: <T = unknown>(keys: string[]) => Promise<(T | undefined)[]>;
54
+ mset: <T = unknown>(entries: {
55
+ key: string;
56
+ value: T;
57
+ ttl?: number;
58
+ }[]) => Promise<void>;
59
+ ttl: (key: string) => Promise<number | null>;
60
+ expire: (key: string, ttl: number) => Promise<boolean>;
61
+ incr: (key: string, delta?: number) => Promise<number>;
62
+ decr: (key: string, delta?: number) => Promise<number>;
63
+ keys: (pattern?: string) => Promise<string[]>;
64
+ flush: () => Promise<void>;
65
+ private startCleanup;
66
+ private cleanupExpired;
67
+ private getFilePath;
68
+ private isExpired;
69
+ private readCacheEntry;
70
+ private writeCacheEntry;
71
+ }
72
+ declare class RedisCacheAdapter implements ICache {
73
+ private client;
74
+ constructor(options?: RedisCacheAdapterType);
75
+ connect(): Promise<void>;
76
+ close(): void;
77
+ /**
78
+ * Get connection status
79
+ */
80
+ get connected(): boolean;
81
+ get<T = unknown>(key: string): Promise<T | undefined>;
82
+ set<T = unknown>(key: string, value: T, ttl?: number): Promise<void>;
83
+ delete(key: string): Promise<boolean>;
84
+ has(key: string): Promise<boolean>;
85
+ mget<T = unknown>(keys: string[]): Promise<(T | undefined)[]>;
86
+ mset<T = unknown>(entries: {
87
+ key: string;
88
+ value: T;
89
+ ttl?: number;
90
+ }[]): Promise<void>;
91
+ ttl(key: string): Promise<number | null>;
92
+ expire(key: string, ttl: number): Promise<boolean>;
93
+ incr(key: string, delta?: number): Promise<number>;
94
+ decr(key: string, delta?: number): Promise<number>;
95
+ keys(pattern?: string): Promise<string[]>;
96
+ flush(): Promise<void>;
97
+ }
98
+ export { RedisCacheAdapterType, RedisCacheAdapter, ICache, FilesystemCacheAdapterType, FilesystemCache, CacheException, CacheClassType };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ var Z=Object.create;var{getPrototypeOf:_,defineProperty:U,getOwnPropertyNames:$}=Object;var L=Object.prototype.hasOwnProperty;var W=(H,I,j)=>{j=H!=null?Z(_(H)):{};let q=I||!H||!H.__esModule?U(j,"default",{value:H,enumerable:!0}):j;for(let B of $(H))if(!L.call(q,B))U(q,B,{get:()=>H[B],enumerable:!0});return q};var X=import.meta.require;import{Exception as M}from"@ooneex/exception";import{HttpStatus as O}from"@ooneex/http-status";class G extends M{constructor(H,I={}){super(H,{status:O.Code.InternalServerError,data:I});this.name="CacheException"}}import{mkdir as b,readdir as D,stat as A}from"fs/promises";class F{cacheDir;maxFileSize;cleanupInterval;enableCleanup;cleanupTimer;constructor(H={}){this.cacheDir=H.cacheDir||`${process.cwd()}/.cache`,this.maxFileSize=H.maxFileSize||10485760,this.cleanupInterval=H.cleanupInterval||300000,this.enableCleanup=H.enableCleanup??!0}async connect(){try{if(await b(this.cacheDir,{recursive:!0}),!(await A(this.cacheDir)).isDirectory())throw new G("Failed to create cache directory");if(this.enableCleanup&&!this.cleanupTimer)this.startCleanup()}catch(H){throw new G(`Failed to initialize filesystem cache: ${H}`)}}async close(){if(this.cleanupTimer)clearInterval(this.cleanupTimer),this.cleanupTimer=void 0}get=async(H)=>{try{return(await this.readCacheEntry(H))?.value}catch(I){throw new G(`Failed to get key "${H}": ${I}`)}};set=async(H,I,j)=>{try{let q={value:I,createdAt:Date.now(),originalKey:H,...j!==void 0&&{ttl:j}};await this.writeCacheEntry(H,q)}catch(q){throw new G(`Failed to set key "${H}": ${q}`)}};delete=async(H)=>{try{let I=Bun.file(this.getFilePath(H));if(!await I.exists())return!1;return await I.delete(),!0}catch(I){throw new G(`Failed to delete key "${H}": ${I}`)}};has=async(H)=>{try{return await this.readCacheEntry(H)!==void 0}catch(I){throw new G(`Failed to check if key "${H}" exists: ${I}`)}};mget=async(H)=>{if(H.length===0)return[];try{let I=[],j=await Promise.allSettled(H.map((q)=>this.readCacheEntry(q)));for(let q of j)if(q.status==="fulfilled")I.push(q.value?.value);else I.push(void 0);return I}catch(I){throw new G(`Failed to get multiple keys: ${I}`)}};mset=async(H)=>{if(H.length===0)return;try{let I=Date.now(),j=H.map(async({key:q,value:B,ttl:J})=>{let P={value:B,createdAt:I,originalKey:q,...J!==void 0&&{ttl:J}};return this.writeCacheEntry(q,P)});await Promise.all(j)}catch(I){throw new G(`Failed to set multiple keys: ${I}`)}};ttl=async(H)=>{try{let I=await this.readCacheEntry(H);if(!I)return-1;if(I.ttl===0)return 0;if(!I.ttl)return null;let j=Math.floor((I.createdAt+I.ttl*1000-Date.now())/1000);return Math.max(0,j)}catch(I){throw new G(`Failed to get TTL for key "${H}": ${I}`)}};expire=async(H,I)=>{try{let j=await this.readCacheEntry(H);if(!j)return!1;if(j.ttl=I,I!==0)j.createdAt=Date.now();return j.originalKey=H,await this.writeCacheEntry(H,j),!0}catch(j){throw new G(`Failed to set TTL for key "${H}": ${j}`)}};incr=async(H,I=1)=>{try{let j=await this.readCacheEntry(H),B=(typeof j?.value==="number"?j.value:0)+I,J={value:B,createdAt:j?.createdAt??Date.now(),originalKey:H,...j?.ttl!==void 0&&{ttl:j.ttl}};return await this.writeCacheEntry(H,J),B}catch(j){throw new G(`Failed to increment key "${H}" by ${I}: ${j}`)}};decr=async(H,I=1)=>{try{let j=await this.readCacheEntry(H),B=(typeof j?.value==="number"?j.value:0)-I,J={value:B,createdAt:j?.createdAt||Date.now(),originalKey:H,...j?.ttl!==void 0&&{ttl:j.ttl}};return await this.writeCacheEntry(H,J),B}catch(j){throw new G(`Failed to decrement key "${H}" by ${I}: ${j}`)}};keys=async(H="*")=>{try{let j=(await D(this.cacheDir)).filter((Q)=>Q.endsWith(".cache")),q=[];for(let Q of j)try{let R=Bun.file(`${this.cacheDir}/${Q}`);if(await R.exists()){let Y=await R.text(),S=JSON.parse(Y);if(S.originalKey)q.push(S.originalKey);else q.push(Q.replace(".cache",""))}}catch{q.push(Q.replace(".cache",""))}let B=q;if(H!=="*"){let Q=new RegExp(H.replace(/\*/g,".*").replace(/\?/g,"."));B=q.filter((R)=>Q.test(R))}let J=await Promise.allSettled(B.map(async(Q)=>{let R=await this.readCacheEntry(Q);return{key:Q,valid:R!==void 0}})),P=[];for(let Q of J)if(Q.status==="fulfilled"&&Q.value.valid)P.push(Q.value.key);return P.sort()}catch(I){throw new G(`Failed to get keys with pattern "${H}": ${I}`)}};flush=async()=>{try{let{readdir:H}=await import("fs/promises"),q=(await H(this.cacheDir)).filter((B)=>B.endsWith(".cache")).map((B)=>{return Bun.file(`${this.cacheDir}/${B}`).delete()});await Promise.all(q)}catch(H){throw new G(`Failed to flush cache: ${H}`)}};startCleanup(){this.cleanupTimer=setInterval(async()=>{try{await this.cleanupExpired()}catch{}},this.cleanupInterval)}async cleanupExpired(){try{let{readdir:H}=await import("fs/promises"),I=await H(this.cacheDir),j=Date.now();for(let q of I){if(!q.endsWith(".cache"))continue;let B=Bun.file(`${this.cacheDir}/${q}`);try{if(await B.exists()){let J=await B.text(),P=JSON.parse(J);if(P.ttl&&P.createdAt+P.ttl*1000<j)await B.delete()}}catch{try{await B.delete()}catch{}}}}catch{}}getFilePath(H){if(H.length>200){let j=Bun.hash(H);return`${this.cacheDir}/${j.toString(36)}.cache`}let I=H.replace(/[<>:"/\\|?*\x00-\x1f]/g,"_");return`${this.cacheDir}/${I}.cache`}async isExpired(H){if(!H.ttl)return!1;if(H.ttl===0)return!1;return H.createdAt+H.ttl*1000<Date.now()}async readCacheEntry(H){try{let I=Bun.file(this.getFilePath(H));if(!await I.exists())return;let j=await I.text(),q=JSON.parse(j);if(await this.isExpired(q)){await I.delete().catch(()=>{});return}return q}catch{return}}async writeCacheEntry(H,I){let j=JSON.stringify(I);if(Buffer.byteLength(j,"utf-8")>this.maxFileSize)throw new G(`Cache entry exceeds maximum file size of ${this.maxFileSize} bytes`);await Bun.write(this.getFilePath(H),j)}}class N{client;constructor(H={}){let I=H.connectionString||Bun.env.CACHE_REDIS_URL;if(!I)throw new G("Redis connection string is required. Please provide a connection string either through the constructor options or set the CACHE_REDIS_URL environment variable.");let{connectionString:j,...q}=H;this.client=new Bun.RedisClient(I,q)}async connect(){await this.client.connect()}close(){this.client.close()}get connected(){return this.client.connected}async get(H){try{let I=await this.client.get(H);if(I===null)return;try{return JSON.parse(I)}catch{return I}}catch(I){throw new G(`Failed to get key "${H}": ${I}`)}}async set(H,I,j){try{let q=I===void 0?null:I,B=typeof q==="string"?q:JSON.stringify(q);if(j)await this.client.send("SETEX",[H,j.toString(),B]);else await this.client.set(H,B)}catch(q){throw new G(`Failed to set key "${H}": ${q}`)}}async delete(H){try{return await this.client.del(H)>0}catch(I){throw new G(`Failed to delete key "${H}": ${I}`)}}async has(H){try{return await this.client.exists(H)}catch(I){throw new G(`Failed to check if key "${H}" exists: ${I}`)}}async mget(H){if(H.length===0)return[];try{return(await this.client.send("MGET",H)).map((j)=>{if(j===null)return;try{return JSON.parse(j)}catch{return j}})}catch(I){throw new G(`Failed to get multiple keys: ${I}`)}}async mset(H){if(H.length===0)return;try{let I=[],j=[];if(H.forEach((q)=>{if(q.ttl&&q.ttl>0)j.push(q);else I.push({key:q.key,value:q.value})}),I.length>0){let q=[];I.forEach(({key:B,value:J})=>{q.push(B);let P=J===void 0?null:J;q.push(typeof P==="string"?P:JSON.stringify(P))}),await this.client.send("MSET",q)}for(let{key:q,value:B,ttl:J}of j){let P=B===void 0?null:B,Q=typeof P==="string"?P:JSON.stringify(P);await this.client.send("SETEX",[q,J.toString(),Q])}}catch(I){throw new G(`Failed to set multiple keys: ${I}`)}}async ttl(H){try{let I=await this.client.ttl(H);if(I===-2)return-1;if(I===-1)return null;return I}catch(I){throw new G(`Failed to get TTL for key "${H}": ${I}`)}}async expire(H,I){try{return await this.client.expire(H,I)===1}catch(j){throw new G(`Failed to set TTL for key "${H}": ${j}`)}}async incr(H,I=1){try{if(I===1)return await this.client.incr(H);let j=Math.floor(I);return await this.client.send("INCRBY",[H,j.toString()])}catch(j){throw new G(`Failed to increment key "${H}" by ${I}: ${j}`)}}async decr(H,I=1){try{if(I===1)return await this.client.decr(H);let j=Math.floor(I);return await this.client.send("DECRBY",[H,j.toString()])}catch(j){throw new G(`Failed to decrement key "${H}" by ${I}: ${j}`)}}async keys(H="*"){try{return await this.client.send("KEYS",[H])}catch(I){throw new G(`Failed to get keys with pattern "${H}": ${I}`)}}async flush(){try{await this.client.send("FLUSHDB",[])}catch(H){throw new G(`Failed to flush database: ${H}`)}}}export{N as RedisCacheAdapter,F as FilesystemCache,G as CacheException};
3
+
4
+ //# debugId=3AA2F052E73C867064756E2164756E21
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["src/CacheException.ts", "src/FilesystemCache.ts", "src/RedisCacheAdapter.ts"],
4
+ "sourcesContent": [
5
+ "import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class CacheException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"CacheException\";\n }\n}\n",
6
+ "import { mkdir, readdir, stat } from \"node:fs/promises\";\nimport { CacheException } from \"./CacheException\";\nimport type { FilesystemCacheAdapterType, ICache } from \"./types\";\n\ntype CacheEntryType<T = unknown> = {\n value: T;\n ttl?: number;\n createdAt: number;\n originalKey: string;\n};\n\nexport class FilesystemCache implements ICache {\n private cacheDir: string;\n private maxFileSize: number;\n private cleanupInterval: number;\n private enableCleanup: boolean;\n private cleanupTimer: Timer | undefined;\n\n constructor(options: FilesystemCacheAdapterType = {}) {\n this.cacheDir = options.cacheDir || `${process.cwd()}/.cache`;\n this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB default\n this.cleanupInterval = options.cleanupInterval || 5 * 60 * 1000; // 5 minutes default\n this.enableCleanup = options.enableCleanup ?? true;\n }\n\n public async connect(): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n\n // Verify directory was created\n const stats = await stat(this.cacheDir);\n if (!stats.isDirectory()) {\n throw new CacheException(\"Failed to create cache directory\");\n }\n\n if (this.enableCleanup && !this.cleanupTimer) {\n this.startCleanup();\n }\n } catch (error) {\n throw new CacheException(`Failed to initialize filesystem cache: ${error}`);\n }\n }\n\n public async close(): Promise<void> {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined as Timer | undefined;\n }\n }\n\n // Basic operations\n public get = async <T = unknown>(key: string): Promise<T | undefined> => {\n try {\n const entry = await this.readCacheEntry<T>(key);\n return entry?.value;\n } catch (error) {\n throw new CacheException(`Failed to get key \"${key}\": ${error}`);\n }\n };\n\n public set = async <T = unknown>(key: string, value: T, ttl?: number): Promise<void> => {\n try {\n const entry: CacheEntryType<T> = {\n value,\n createdAt: Date.now(),\n originalKey: key,\n ...(ttl !== undefined && { ttl }),\n };\n\n await this.writeCacheEntry(key, entry);\n } catch (error) {\n throw new CacheException(`Failed to set key \"${key}\": ${error}`);\n }\n };\n\n public delete = async (key: string): Promise<boolean> => {\n try {\n const file = Bun.file(this.getFilePath(key));\n\n if (!(await file.exists())) {\n return false;\n }\n\n await file.delete();\n return true;\n } catch (error) {\n throw new CacheException(`Failed to delete key \"${key}\": ${error}`);\n }\n };\n\n public has = async (key: string): Promise<boolean> => {\n try {\n const entry = await this.readCacheEntry(key);\n return entry !== undefined;\n } catch (error) {\n throw new CacheException(`Failed to check if key \"${key}\" exists: ${error}`);\n }\n };\n\n // Bulk operations\n public mget = async <T = unknown>(keys: string[]): Promise<(T | undefined)[]> => {\n if (keys.length === 0) {\n return [];\n }\n\n try {\n const results: (T | undefined)[] = [];\n\n // Use Promise.all for concurrent reads\n const entries = await Promise.allSettled(keys.map((key) => this.readCacheEntry<T>(key)));\n\n for (const result of entries) {\n if (result.status === \"fulfilled\") {\n results.push(result.value?.value);\n } else {\n results.push(undefined);\n }\n }\n\n return results;\n } catch (error) {\n throw new CacheException(`Failed to get multiple keys: ${error}`);\n }\n };\n\n public mset = async <T = unknown>(entries: { key: string; value: T; ttl?: number }[]): Promise<void> => {\n if (entries.length === 0) {\n return;\n }\n\n try {\n const now = Date.now();\n\n // Use Promise.all for concurrent writes\n const promises = entries.map(async ({ key, value, ttl }) => {\n const entry: CacheEntryType<T> = {\n value,\n createdAt: now,\n originalKey: key,\n ...(ttl !== undefined && { ttl }),\n };\n\n return this.writeCacheEntry(key, entry);\n });\n\n await Promise.all(promises);\n } catch (error) {\n throw new CacheException(`Failed to set multiple keys: ${error}`);\n }\n };\n\n // TTL / metadata\n public ttl = async (key: string): Promise<number | null> => {\n try {\n const entry = await this.readCacheEntry(key);\n\n if (!entry) {\n return -1; // Key not found\n }\n\n // Special handling for zero TTL - should return 0 if it was set with 0 TTL\n if (entry.ttl === 0) {\n return 0;\n }\n\n if (!entry.ttl) {\n return null; // No TTL\n }\n\n const remaining = Math.floor((entry.createdAt + entry.ttl * 1000 - Date.now()) / 1000);\n return Math.max(0, remaining);\n } catch (error) {\n throw new CacheException(`Failed to get TTL for key \"${key}\": ${error}`);\n }\n };\n\n public expire = async (key: string, ttl: number): Promise<boolean> => {\n try {\n const entry = await this.readCacheEntry(key);\n\n if (!entry) {\n return false;\n }\n\n // For zero TTL, mark it but don't update createdAt to maintain the \"zero\" state\n entry.ttl = ttl;\n if (ttl !== 0) {\n entry.createdAt = Date.now();\n }\n entry.originalKey = key; // Ensure original key is preserved\n\n await this.writeCacheEntry(key, entry);\n return true;\n } catch (error) {\n throw new CacheException(`Failed to set TTL for key \"${key}\": ${error}`);\n }\n };\n\n // Counters (atomic operations with file-based locking)\n public incr = async (key: string, delta = 1): Promise<number> => {\n try {\n const entry = await this.readCacheEntry<number>(key);\n const currentValue = typeof entry?.value === \"number\" ? entry.value : 0;\n const newValue = currentValue + delta;\n\n const newEntry: CacheEntryType<number> = {\n value: newValue,\n createdAt: entry?.createdAt ?? Date.now(),\n originalKey: key,\n ...(entry?.ttl !== undefined && { ttl: entry.ttl }),\n };\n\n await this.writeCacheEntry(key, newEntry);\n return newValue;\n } catch (error) {\n throw new CacheException(`Failed to increment key \"${key}\" by ${delta}: ${error}`);\n }\n };\n\n public decr = async (key: string, delta = 1): Promise<number> => {\n try {\n const entry = await this.readCacheEntry<number>(key);\n const currentValue = typeof entry?.value === \"number\" ? entry.value : 0;\n const newValue = currentValue - delta;\n\n const newEntry: CacheEntryType<number> = {\n value: newValue,\n createdAt: entry?.createdAt || Date.now(),\n originalKey: key,\n ...(entry?.ttl !== undefined && { ttl: entry.ttl }),\n };\n\n await this.writeCacheEntry(key, newEntry);\n return newValue;\n } catch (error) {\n throw new CacheException(`Failed to decrement key \"${key}\" by ${delta}: ${error}`);\n }\n };\n\n // Maintenance\n public keys = async (pattern = \"*\"): Promise<string[]> => {\n try {\n const files = await readdir(this.cacheDir);\n const cacheFiles = files.filter((file) => file.endsWith(\".cache\"));\n\n // Read cache files to get original keys\n const keys: string[] = [];\n\n for (const file of cacheFiles) {\n try {\n const cacheFile = Bun.file(`${this.cacheDir}/${file}`);\n if (await cacheFile.exists()) {\n const content = await cacheFile.text();\n const entry = JSON.parse(content);\n\n // Use the original key stored in the entry\n if (entry.originalKey) {\n keys.push(entry.originalKey);\n } else {\n // Fallback to filename without extension\n keys.push(file.replace(\".cache\", \"\"));\n }\n }\n } catch {\n // If we can't read the file, use the filename as key\n keys.push(file.replace(\".cache\", \"\"));\n }\n }\n\n // Simple pattern matching\n let filteredKeys = keys;\n if (pattern !== \"*\") {\n const regex = new RegExp(pattern.replace(/\\*/g, \".*\").replace(/\\?/g, \".\"));\n filteredKeys = keys.filter((key) => regex.test(key));\n }\n\n // Filter out expired keys using concurrent checks\n const validityChecks = await Promise.allSettled(\n filteredKeys.map(async (key) => {\n const entry = await this.readCacheEntry(key);\n return { key, valid: entry !== undefined };\n }),\n );\n\n const validKeys: string[] = [];\n for (const result of validityChecks) {\n if (result.status === \"fulfilled\" && result.value.valid) {\n validKeys.push(result.value.key);\n }\n }\n\n return validKeys.sort();\n } catch (error) {\n throw new CacheException(`Failed to get keys with pattern \"${pattern}\": ${error}`);\n }\n };\n\n public flush = async (): Promise<void> => {\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const files = await readdir(this.cacheDir);\n const cacheFiles = files.filter((file) => file.endsWith(\".cache\"));\n\n // Use Promise.all for concurrent deletions\n const promises = cacheFiles.map((fileName) => {\n const file = Bun.file(`${this.cacheDir}/${fileName}`);\n return file.delete();\n });\n\n await Promise.all(promises);\n } catch (error) {\n throw new CacheException(`Failed to flush cache: ${error}`);\n }\n };\n\n private startCleanup(): void {\n this.cleanupTimer = setInterval(async () => {\n try {\n await this.cleanupExpired();\n } catch {\n // Silent fail for cleanup\n }\n }, this.cleanupInterval);\n }\n\n private async cleanupExpired(): Promise<void> {\n try {\n const { readdir } = await import(\"node:fs/promises\");\n const files = await readdir(this.cacheDir);\n const now = Date.now();\n\n for (const fileName of files) {\n if (!fileName.endsWith(\".cache\")) continue;\n\n const file = Bun.file(`${this.cacheDir}/${fileName}`);\n try {\n if (await file.exists()) {\n const content = await file.text();\n const entry: CacheEntryType = JSON.parse(content);\n\n if (entry.ttl && entry.createdAt + entry.ttl * 1000 < now) {\n await file.delete();\n }\n }\n } catch {\n // If we can't read/parse a file, it might be corrupted, so delete it\n try {\n await file.delete();\n } catch {\n // Silent fail\n }\n }\n }\n } catch {\n // Silent fail for cleanup\n }\n }\n\n private getFilePath(key: string): string {\n // Handle very long keys by using hash instead of truncation\n if (key.length > 200) {\n const hash = Bun.hash(key);\n return `${this.cacheDir}/${hash.toString(36)}.cache`;\n }\n\n // Sanitize key for filesystem - only replace characters that are problematic for file names\n const sanitizedKey = key.replace(/[<>:\"/\\\\|?*\\x00-\\x1f]/g, \"_\");\n return `${this.cacheDir}/${sanitizedKey}.cache`;\n }\n\n private async isExpired(entry: CacheEntryType): Promise<boolean> {\n if (!entry.ttl) return false;\n\n // Special case for zero TTL - should not be considered expired for immediate reads\n // Zero TTL means immediate expiration but should still be readable momentarily\n if (entry.ttl === 0) {\n return false; // Don't auto-expire zero TTL entries in readCacheEntry\n }\n\n return entry.createdAt + entry.ttl * 1000 < Date.now();\n }\n\n private async readCacheEntry<T>(key: string): Promise<CacheEntryType<T> | undefined> {\n try {\n const file = Bun.file(this.getFilePath(key));\n\n if (!(await file.exists())) {\n return;\n }\n\n const content = await file.text();\n const entry: CacheEntryType<T> = JSON.parse(content);\n\n if (await this.isExpired(entry)) {\n // Clean up expired entry\n await file.delete().catch(() => {});\n return;\n }\n\n return entry;\n } catch {\n // For any read errors, assume file doesn't exist or is corrupted\n return;\n }\n }\n\n private async writeCacheEntry<T>(key: string, entry: CacheEntryType<T>): Promise<void> {\n const content = JSON.stringify(entry);\n\n if (Buffer.byteLength(content, \"utf-8\") > this.maxFileSize) {\n throw new CacheException(`Cache entry exceeds maximum file size of ${this.maxFileSize} bytes`);\n }\n\n await Bun.write(this.getFilePath(key), content);\n }\n}\n",
7
+ "import { CacheException } from \"./CacheException\";\nimport type { ICache, RedisCacheAdapterType } from \"./types\";\n\nexport class RedisCacheAdapter implements ICache {\n private client: Bun.RedisClient;\n\n constructor(options: RedisCacheAdapterType = {}) {\n const connectionString = options.connectionString || Bun.env.CACHE_REDIS_URL;\n\n if (!connectionString) {\n throw new CacheException(\n \"Redis connection string is required. Please provide a connection string either through the constructor options or set the CACHE_REDIS_URL environment variable.\",\n );\n }\n\n const { connectionString: _, ...clientOptions } = options;\n\n this.client = new Bun.RedisClient(connectionString, clientOptions);\n }\n\n public async connect(): Promise<void> {\n await this.client.connect();\n }\n\n public close(): void {\n this.client.close();\n }\n\n /**\n * Get connection status\n */\n public get connected(): boolean {\n return this.client.connected;\n }\n\n // Basic operations\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n try {\n const value = await this.client.get(key);\n if (value === null) {\n return;\n }\n\n // Try to parse as JSON, fallback to raw value\n try {\n return JSON.parse(value);\n } catch {\n return value as T;\n }\n } catch (error) {\n throw new CacheException(`Failed to get key \"${key}\": ${error}`);\n }\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n try {\n // Convert undefined to null for Redis compatibility\n const normalizedValue = value === undefined ? null : value;\n const serializedValue = typeof normalizedValue === \"string\" ? normalizedValue : JSON.stringify(normalizedValue);\n\n if (ttl) {\n await this.client.send(\"SETEX\", [key, ttl.toString(), serializedValue]);\n } else {\n await this.client.set(key, serializedValue);\n }\n } catch (error) {\n throw new CacheException(`Failed to set key \"${key}\": ${error}`);\n }\n }\n\n public async delete(key: string): Promise<boolean> {\n try {\n const result = await this.client.del(key);\n return result > 0;\n } catch (error) {\n throw new CacheException(`Failed to delete key \"${key}\": ${error}`);\n }\n }\n\n public async has(key: string): Promise<boolean> {\n try {\n return await this.client.exists(key);\n } catch (error) {\n throw new CacheException(`Failed to check if key \"${key}\" exists: ${error}`);\n }\n }\n\n // Bulk operations\n public async mget<T = unknown>(keys: string[]): Promise<(T | undefined)[]> {\n if (keys.length === 0) {\n return [];\n }\n\n try {\n const values = await this.client.send(\"MGET\", keys);\n return values.map((value: string | null) => {\n if (value === null) {\n return undefined;\n }\n\n // Try to parse as JSON, fallback to raw value\n try {\n return JSON.parse(value);\n } catch {\n return value as T;\n }\n });\n } catch (error) {\n throw new CacheException(`Failed to get multiple keys: ${error}`);\n }\n }\n\n public async mset<T = unknown>(entries: { key: string; value: T; ttl?: number }[]): Promise<void> {\n if (entries.length === 0) {\n return;\n }\n\n try {\n // Group entries by TTL\n const withoutTtl: { key: string; value: T }[] = [];\n const withTtl: { key: string; value: T; ttl: number }[] = [];\n\n entries.forEach((entry) => {\n if (entry.ttl && entry.ttl > 0) {\n withTtl.push(entry as { key: string; value: T; ttl: number });\n } else {\n withoutTtl.push({ key: entry.key, value: entry.value });\n }\n });\n\n // Handle entries without TTL using MSET\n if (withoutTtl.length > 0) {\n const msetArgs: string[] = [];\n withoutTtl.forEach(({ key, value }) => {\n msetArgs.push(key);\n // Convert undefined to null for Redis compatibility\n const normalizedValue = value === undefined ? null : value;\n msetArgs.push(typeof normalizedValue === \"string\" ? normalizedValue : JSON.stringify(normalizedValue));\n });\n await this.client.send(\"MSET\", msetArgs);\n }\n\n // Handle entries with TTL individually using SETEX\n for (const { key, value, ttl } of withTtl) {\n // Convert undefined to null for Redis compatibility\n const normalizedValue = value === undefined ? null : value;\n const serializedValue = typeof normalizedValue === \"string\" ? normalizedValue : JSON.stringify(normalizedValue);\n await this.client.send(\"SETEX\", [key, ttl.toString(), serializedValue]);\n }\n } catch (error) {\n throw new CacheException(`Failed to set multiple keys: ${error}`);\n }\n }\n\n // TTL / metadata\n public async ttl(key: string): Promise<number | null> {\n try {\n const result = await this.client.ttl(key);\n\n // Redis TTL returns:\n // -2 if key does not exist\n // -1 if key exists but has no TTL\n // positive number for remaining seconds\n if (result === -2) {\n return -1; // Key not found (following interface spec)\n }\n if (result === -1) {\n return null; // No TTL\n }\n return result; // Remaining seconds\n } catch (error) {\n throw new CacheException(`Failed to get TTL for key \"${key}\": ${error}`);\n }\n }\n\n public async expire(key: string, ttl: number): Promise<boolean> {\n try {\n const result = await this.client.expire(key, ttl);\n return result === 1;\n } catch (error) {\n throw new CacheException(`Failed to set TTL for key \"${key}\": ${error}`);\n }\n }\n\n // Counters (atomic operations)\n public async incr(key: string, delta = 1): Promise<number> {\n try {\n if (delta === 1) {\n return await this.client.incr(key);\n }\n const integerDelta = Math.floor(delta);\n return await this.client.send(\"INCRBY\", [key, integerDelta.toString()]);\n } catch (error) {\n throw new CacheException(`Failed to increment key \"${key}\" by ${delta}: ${error}`);\n }\n }\n\n public async decr(key: string, delta = 1): Promise<number> {\n try {\n if (delta === 1) {\n return await this.client.decr(key);\n }\n const integerDelta = Math.floor(delta);\n return await this.client.send(\"DECRBY\", [key, integerDelta.toString()]);\n } catch (error) {\n throw new CacheException(`Failed to decrement key \"${key}\" by ${delta}: ${error}`);\n }\n }\n\n // Maintenance\n public async keys(pattern = \"*\"): Promise<string[]> {\n try {\n return await this.client.send(\"KEYS\", [pattern]);\n } catch (error) {\n throw new CacheException(`Failed to get keys with pattern \"${pattern}\": ${error}`);\n }\n }\n\n public async flush(): Promise<void> {\n try {\n await this.client.send(\"FLUSHDB\", []);\n } catch (error) {\n throw new CacheException(`Failed to flush database: ${error}`);\n }\n }\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "3AA2F052E73C867064756E2164756E21",
11
+ "names": []
12
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ooneex/cache",
3
+ "description": "",
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "LICENSE",
9
+ "README.md",
10
+ "package.json"
11
+ ],
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "license": "MIT",
24
+ "scripts": {
25
+ "test": "bun test tests",
26
+ "build": "bunup",
27
+ "lint": "tsgo --noEmit && bunx biome lint",
28
+ "publish:prod": "bun publish --tolerate-republish --access public",
29
+ "publish:pack": "bun pm pack --destination ./dist",
30
+ "publish:dry": "bun publish --dry-run"
31
+ },
32
+ "dependencies": {
33
+ "@ooneex/exception": "0.0.1",
34
+ "@ooneex/http-status": "0.0.1"
35
+ },
36
+ "devDependencies": {},
37
+ "peerDependencies": {}
38
+ }