@devbro/neko-cache 0.1.2 → 0.1.3

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/cache.d.mts CHANGED
@@ -1,5 +1,5 @@
1
+ import { JSONValue } from '@devbro/neko-helper';
1
2
  import { CacheProviderInterface } from './CacheProviderInterface.mjs';
2
- import '@devbro/neko-helper';
3
3
 
4
4
  type cacheOptions = {
5
5
  ttl?: number;
@@ -7,11 +7,17 @@ type cacheOptions = {
7
7
  declare class Cache {
8
8
  private provider;
9
9
  constructor(provider: CacheProviderInterface);
10
- get<T>(key: string): Promise<T | undefined>;
11
- put(key: string, value: any, ttl?: number): Promise<void>;
12
- delete(key: string): Promise<void>;
13
- has(key: string): Promise<boolean>;
14
- remember<T>(key: string, callback: () => Promise<T>, options?: cacheOptions): Promise<T>;
10
+ get<T>(key: JSONValue): Promise<T | undefined>;
11
+ put(key: JSONValue, value: any, ttl?: number): Promise<void>;
12
+ delete(key: JSONValue): Promise<void>;
13
+ has(key: JSONValue): Promise<boolean>;
14
+ remember<T>(key: JSONValue, callback: () => Promise<T>, options?: cacheOptions): Promise<T>;
15
+ /**
16
+ * Generates a cache key by serializing and concatenating the provided parts.
17
+ * @param parts
18
+ * @returns
19
+ */
20
+ generateKey(key: JSONValue): string;
15
21
  }
16
22
 
17
23
  export { Cache, type cacheOptions };
package/dist/cache.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { createHash } from "crypto";
3
4
  class Cache {
4
5
  constructor(provider) {
5
6
  this.provider = provider;
@@ -8,16 +9,16 @@ class Cache {
8
9
  __name(this, "Cache");
9
10
  }
10
11
  async get(key) {
11
- return this.provider.get(key);
12
+ return this.provider.get(this.generateKey(key));
12
13
  }
13
14
  async put(key, value, ttl) {
14
- return this.provider.put(key, value, ttl);
15
+ return this.provider.put(this.generateKey(key), value, ttl);
15
16
  }
16
17
  async delete(key) {
17
- return this.provider.delete(key);
18
+ return this.provider.delete(this.generateKey(key));
18
19
  }
19
20
  async has(key) {
20
- return this.provider.has(key);
21
+ return this.provider.has(this.generateKey(key));
21
22
  }
22
23
  async remember(key, callback, options = {}) {
23
24
  options.ttl = options.ttl ?? 3600;
@@ -29,6 +30,14 @@ class Cache {
29
30
  await this.put(key, result, options.ttl);
30
31
  return result;
31
32
  }
33
+ /**
34
+ * Generates a cache key by serializing and concatenating the provided parts.
35
+ * @param parts
36
+ * @returns
37
+ */
38
+ generateKey(key) {
39
+ return createHash("md5").update(JSON.stringify(key)).digest("hex");
40
+ }
32
41
  }
33
42
  export {
34
43
  Cache
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cache.mts"],"sourcesContent":["import { CacheProviderInterface } from './CacheProviderInterface.mjs';\n\nexport type cacheOptions = {\n ttl?: number;\n};\n\nexport class Cache {\n constructor(private provider: CacheProviderInterface) {}\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.provider.get(key) as Promise<T | undefined>;\n }\n\n async put(key: string, value: any, ttl?: number): Promise<void> {\n return this.provider.put(key, value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n return this.provider.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n return this.provider.has(key);\n }\n\n async remember<T>(\n key: string,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n}\n"],"mappings":";;AAMO,MAAM,MAAM;AAAA,EACjB,YAAoB,UAAkC;AAAlC;AAAA,EAAmC;AAAA,EAPzD,OAMmB;AAAA;AAAA;AAAA,EAGjB,MAAM,IAAO,KAAqC;AAChD,WAAO,KAAK,SAAS,IAAI,GAAG;AAAA,EAC9B;AAAA,EAEA,MAAM,IAAI,KAAa,OAAY,KAA6B;AAC9D,WAAO,KAAK,SAAS,IAAI,KAAK,OAAO,GAAG;AAAA,EAC1C;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,WAAO,KAAK,SAAS,OAAO,GAAG;AAAA,EACjC;AAAA,EAEA,MAAM,IAAI,KAA+B;AACvC,WAAO,KAAK,SAAS,IAAI,GAAG;AAAA,EAC9B;AAAA,EAEA,MAAM,SACJ,KACA,UACA,UAAwB,CAAC,GACb;AACZ,YAAQ,MAAM,QAAQ,OAAO;AAE7B,UAAM,SAAS,MAAM,KAAK,IAAO,GAAG;AACpC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM,SAAS;AAC9B,UAAM,KAAK,IAAI,KAAK,QAAQ,QAAQ,GAAG;AACvC,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/cache.mts"],"sourcesContent":["import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\nexport type cacheOptions = {\n ttl?: number;\n};\n\nexport class Cache {\n constructor(private provider: CacheProviderInterface) {}\n\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and concatenating the provided parts.\n * @param parts\n * @returns\n */\n generateKey(key: JSONValue): string {\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n"],"mappings":";;AAEA,SAAS,kBAAkB;AAMpB,MAAM,MAAM;AAAA,EACjB,YAAoB,UAAkC;AAAlC;AAAA,EAAmC;AAAA,EATzD,OAQmB;AAAA;AAAA;AAAA,EAGjB,MAAM,IAAO,KAAwC;AACnD,WAAO,KAAK,SAAS,IAAI,KAAK,YAAY,GAAG,CAAC;AAAA,EAChD;AAAA,EAEA,MAAM,IAAI,KAAgB,OAAY,KAA6B;AACjE,WAAO,KAAK,SAAS,IAAI,KAAK,YAAY,GAAG,GAAG,OAAO,GAAG;AAAA,EAC5D;AAAA,EAEA,MAAM,OAAO,KAA+B;AAC1C,WAAO,KAAK,SAAS,OAAO,KAAK,YAAY,GAAG,CAAC;AAAA,EACnD;AAAA,EAEA,MAAM,IAAI,KAAkC;AAC1C,WAAO,KAAK,SAAS,IAAI,KAAK,YAAY,GAAG,CAAC;AAAA,EAChD;AAAA,EAEA,MAAM,SACJ,KACA,UACA,UAAwB,CAAC,GACb;AACZ,YAAQ,MAAM,QAAQ,OAAO;AAE7B,UAAM,SAAS,MAAM,KAAK,IAAO,GAAG;AACpC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,MAAM,SAAS;AAC9B,UAAM,KAAK,IAAI,KAAK,QAAQ,QAAQ,GAAG;AACvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,KAAwB;AAClC,WAAO,WAAW,KAAK,EAAE,OAAO,KAAK,UAAU,GAAG,CAAC,EAAE,OAAO,KAAK;AAAA,EACnE;AACF;","names":[]}
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ __export(index_exports, {
41
41
  module.exports = __toCommonJS(index_exports);
42
42
 
43
43
  // src/cache.mts
44
+ var import_crypto = require("crypto");
44
45
  var Cache = class {
45
46
  constructor(provider) {
46
47
  this.provider = provider;
@@ -49,16 +50,16 @@ var Cache = class {
49
50
  __name(this, "Cache");
50
51
  }
51
52
  async get(key) {
52
- return this.provider.get(key);
53
+ return this.provider.get(this.generateKey(key));
53
54
  }
54
55
  async put(key, value, ttl) {
55
- return this.provider.put(key, value, ttl);
56
+ return this.provider.put(this.generateKey(key), value, ttl);
56
57
  }
57
58
  async delete(key) {
58
- return this.provider.delete(key);
59
+ return this.provider.delete(this.generateKey(key));
59
60
  }
60
61
  async has(key) {
61
- return this.provider.has(key);
62
+ return this.provider.has(this.generateKey(key));
62
63
  }
63
64
  async remember(key, callback, options = {}) {
64
65
  options.ttl = options.ttl ?? 3600;
@@ -70,6 +71,14 @@ var Cache = class {
70
71
  await this.put(key, result, options.ttl);
71
72
  return result;
72
73
  }
74
+ /**
75
+ * Generates a cache key by serializing and concatenating the provided parts.
76
+ * @param parts
77
+ * @returns
78
+ */
79
+ generateKey(key) {
80
+ return (0, import_crypto.createHash)("md5").update(JSON.stringify(key)).digest("hex");
81
+ }
73
82
  };
74
83
 
75
84
  // src/providers/RedisCacheProvider.mts
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { CacheProviderInterface } from './CacheProviderInterface.mjs';\n\nexport type cacheOptions = {\n ttl?: number;\n};\n\nexport class Cache {\n constructor(private provider: CacheProviderInterface) {}\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.provider.get(key) as Promise<T | undefined>;\n }\n\n async put(key: string, value: any, ttl?: number): Promise<void> {\n return this.provider.put(key, value, ttl);\n }\n\n async delete(key: string): Promise<void> {\n return this.provider.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n return this.provider.has(key);\n }\n\n async remember<T>(\n key: string,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\nexport interface FileCacheConfig {\n cacheDirectory?: string;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n}\n\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\nexport interface MemoryCacheConfig {\n maxSize?: number;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n lastAccessed: number;\n}\n\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n}\n","import { CacheProviderInterface } from \"@/CacheProviderInterface.mjs\";\nimport { JSONValue, JSONObject } from \"@devbro/neko-helper\";\nimport Memcached from \"memcached\";\n\nexport interface MemcachedConfig {\n location?: Memcached.Location;\n options?: Memcached.options;\n}\n\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n \n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n\n\n}","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class DisabledCacheProvider implements CacheProviderInterface {\n constructor(private config = {}) {}\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n async delete(key: string): Promise<void> {}\n\n async has(key: string): Promise<boolean> {\n return false;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cache.mts","../src/providers/RedisCacheProvider.mts","../src/providers/FileCacheProvider.mts","../src/providers/MemoryCacheProvider.mts","../src/providers/MemcacheCacheProvider.mts","../src/providers/DisabledCacheProvider.mts"],"sourcesContent":["export * from './cache.mjs';\nexport * from './CacheProviderInterface.mjs';\nexport * from './providers/index.mjs';\n","import { JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from './CacheProviderInterface.mjs';\nimport { createHash } from 'crypto';\n\nexport type cacheOptions = {\n ttl?: number;\n};\n\nexport class Cache {\n constructor(private provider: CacheProviderInterface) {}\n\n async get<T>(key: JSONValue): Promise<T | undefined> {\n return this.provider.get(this.generateKey(key)) as Promise<T | undefined>;\n }\n\n async put(key: JSONValue, value: any, ttl?: number): Promise<void> {\n return this.provider.put(this.generateKey(key), value, ttl);\n }\n\n async delete(key: JSONValue): Promise<void> {\n return this.provider.delete(this.generateKey(key));\n }\n\n async has(key: JSONValue): Promise<boolean> {\n return this.provider.has(this.generateKey(key));\n }\n\n async remember<T>(\n key: JSONValue,\n callback: () => Promise<T>,\n options: cacheOptions = {}\n ): Promise<T> {\n options.ttl = options.ttl ?? 3600; // default TTL 1 hour\n\n const cached = await this.get<T>(key);\n if (cached) {\n return cached;\n }\n\n const result = await callback();\n await this.put(key, result, options.ttl);\n return result;\n }\n\n /**\n * Generates a cache key by serializing and concatenating the provided parts.\n * @param parts\n * @returns\n */\n generateKey(key: JSONValue): string {\n return createHash('md5').update(JSON.stringify(key)).digest('hex');\n }\n}\n","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class RedisCacheProvider implements CacheProviderInterface {\n private client: RedisClientType;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: RedisClientOptions) {\n this.client = this.createRedisClient();\n this.client.connect();\n }\n\n private createRedisClient(): any {\n let rc = createClient(this.config);\n return rc;\n }\n\n private async ensureConnection(): Promise<void> {\n if (!this.client.isOpen) {\n await this.client.connect();\n }\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n await this.ensureConnection();\n let rc = this.client.get(key);\n return rc.then((value) => {\n if (value === null || value === undefined) {\n return undefined;\n }\n return JSON.parse(value);\n });\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {\n await this.ensureConnection();\n const serializedValue = JSON.stringify(value);\n ttl = ttl ?? this.defaultTTL;\n if (ttl && ttl > 0) {\n await this.client.setEx(key, ttl, serializedValue);\n } else {\n await this.client.set(key, serializedValue);\n }\n }\n\n async delete(key: string): Promise<void> {\n await this.ensureConnection();\n await this.client.del(key);\n }\n\n async has(key: string): Promise<boolean> {\n await this.ensureConnection();\n const result = await this.client.exists(key);\n return result === 1;\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONObject, JSONValue } from '@devbro/neko-helper';\n\nexport interface FileCacheConfig {\n cacheDirectory?: string;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n}\n\nexport class FileCacheProvider implements CacheProviderInterface {\n private config: FileCacheConfig = {\n cacheDirectory: path.join(process.cwd(), 'cache'),\n defaultTTL: 3600 * 1000,\n cleanupInterval: 300 * 1000,\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: FileCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.ensureCacheDirectory();\n this.startCleanupTimer();\n }\n\n private async ensureCacheDirectory(): Promise<void> {\n try {\n await fs.access(this.config.cacheDirectory!);\n } catch {\n await fs.mkdir(this.config.cacheDirectory!, { recursive: true });\n }\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries().catch(console.error);\n }, this.config.cleanupInterval!);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private getFilePath(key: string): string {\n // Create a safe filename from the key\n const safeKey = key.replace(/[^a-z0-9]/gi, '_');\n return path.join(this.config.cacheDirectory!, `${safeKey}.json`);\n }\n\n private async cleanupExpiredEntries(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDirectory!);\n const now = Date.now();\n\n for (const file of files) {\n if (file.endsWith('.json')) {\n const filePath = path.join(this.config.cacheDirectory!, file);\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n if (item.expiresAt && item.expiresAt < now) {\n await fs.unlink(filePath);\n }\n } catch {\n // If file is corrupted, delete it\n await fs.unlink(filePath).catch(() => {});\n }\n }\n }\n } catch (error) {\n // Ignore cleanup errors\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const filePath = this.getFilePath(key);\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const item: CacheItem = JSON.parse(content);\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n await fs.unlink(filePath).catch(() => {});\n return undefined;\n }\n\n return item.value;\n } catch (error) {\n return undefined;\n }\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const filePath = this.getFilePath(key);\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.ensureCacheDirectory();\n await fs.writeFile(filePath, JSON.stringify(item), 'utf-8');\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.getFilePath(key);\n\n try {\n await fs.unlink(filePath);\n } catch {\n // File doesn't exist, that's fine\n }\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== undefined;\n }\n}\n","import { JSONObject, JSONValue } from '@devbro/neko-helper';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\n\nexport interface MemoryCacheConfig {\n maxSize?: number;\n defaultTTL?: number;\n cleanupInterval?: number;\n}\n\ninterface CacheItem {\n value: any;\n expiresAt?: number;\n createdAt: number;\n lastAccessed: number;\n}\n\nexport class MemoryCacheProvider implements CacheProviderInterface {\n private cache = new Map<string, CacheItem>();\n private config: MemoryCacheConfig = {\n maxSize: 1000,\n defaultTTL: 3600,\n cleanupInterval: 600, // 10 minutes\n };\n\n private cleanupTimer?: NodeJS.Timeout;\n\n constructor(config: MemoryCacheConfig = {}) {\n this.config = { ...this.config, ...config };\n\n this.startCleanupTimer();\n }\n\n private startCleanupTimer(): void {\n if (this.config.cleanupInterval! > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanupExpiredEntries();\n }, this.config.cleanupInterval! * 1000);\n }\n }\n\n private stopCleanupTimer(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private cleanupExpiredEntries(): void {\n const now = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.expiresAt && item.expiresAt < now) {\n this.cache.delete(key);\n }\n }\n }\n\n private evictLRU(): void {\n if (this.cache.size <= this.config.maxSize!) {\n return;\n }\n\n // Find the least recently accessed item\n let oldestKey: string | null = null;\n let oldestTime = Date.now();\n\n for (const [key, item] of this.cache.entries()) {\n if (item.lastAccessed < oldestTime) {\n oldestTime = item.lastAccessed;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.cache.delete(oldestKey);\n }\n }\n\n async get(key: string): Promise<JSONObject | JSONValue | undefined> {\n const item = this.cache.get(key);\n\n if (!item) {\n return undefined;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Update last accessed time for LRU\n item.lastAccessed = Date.now();\n\n return item.value;\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n const now = Date.now();\n const effectiveTTL = ttl ?? this.config.defaultTTL!;\n\n const item: CacheItem = {\n value,\n createdAt: now,\n lastAccessed: now,\n expiresAt: effectiveTTL > 0 ? now + effectiveTTL * 1000 : undefined,\n };\n\n this.cache.set(key, item);\n\n // Evict items if we exceed maxSize\n this.evictLRU();\n }\n\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n const item = this.cache.get(key);\n\n if (!item) {\n return false;\n }\n\n // Check if item has expired\n if (item.expiresAt && item.expiresAt < Date.now()) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n}\n","import { CacheProviderInterface } from \"@/CacheProviderInterface.mjs\";\nimport { JSONValue, JSONObject } from \"@devbro/neko-helper\";\nimport Memcached from \"memcached\";\n\nexport interface MemcachedConfig {\n location?: Memcached.Location;\n options?: Memcached.options;\n}\n\nexport class MemcacheCacheProvider implements CacheProviderInterface {\n private client: Memcached;\n private defaultTTL: number = 3600; // default TTL in seconds\n\n constructor(private config: MemcachedConfig = {}) {\n this.client = new Memcached(config.location || 'localhost:11211', config.options || {});\n }\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n \n if (data === undefined || data === null) {\n resolve(undefined);\n return;\n }\n\n try {\n // Memcached automatically handles JSON serialization/deserialization\n // but we need to ensure we return the correct type\n resolve(typeof data === 'string' ? JSON.parse(data) : data);\n } catch (parseErr) {\n // If parsing fails, return the raw value\n resolve(data);\n }\n });\n });\n }\n\n async put(key: string, value: JSONObject | JSONValue, ttl?: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const serializedValue = JSON.stringify(value);\n const finalTTL = ttl ?? this.defaultTTL;\n\n this.client.set(key, serializedValue, finalTTL, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async delete(key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n this.client.del(key, (err: Error | undefined) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n }\n\n async has(key: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n this.client.get(key, (err: Error | undefined, data: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(data !== undefined && data !== null);\n });\n });\n }\n\n\n\n}","import { createClient, RedisClientOptions, RedisClientType } from 'redis';\nimport { CacheProviderInterface } from '../CacheProviderInterface.mjs';\nimport { JSONValue, JSONObject } from '@devbro/neko-helper';\n\nexport class DisabledCacheProvider implements CacheProviderInterface {\n constructor(private config = {}) {}\n\n async get(key: string): Promise<JSONValue | JSONObject | undefined> {\n return undefined;\n }\n\n async put(key: string, value: JSONValue | JSONObject, ttl?: number): Promise<void> {}\n\n async delete(key: string): Promise<void> {}\n\n async has(key: string): Promise<boolean> {\n return false;\n }\n}\n"],"mappings":"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","names":["Memcached"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devbro/neko-cache",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "driver agnostic caching implementation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",