@claude-vector/core
Version:
Core vector search engine for code intelligence
172 lines (147 loc) • 3.96 kB
JavaScript
/**
* Simple file-based cache implementation
*/
import fs from 'fs/promises';
import path from 'path';
import crypto from 'crypto';
export class SimpleCache {
constructor(cachePath, ttl = 3600) {
this.cachePath = cachePath;
this.ttl = ttl * 1000; // Convert seconds to milliseconds
}
/**
* Generate cache key hash
*/
hashKey(key) {
return crypto.createHash('md5').update(key).digest('hex');
}
/**
* Get value from cache
*/
async get(key) {
try {
const hash = this.hashKey(key);
const filePath = path.join(this.cachePath, `${hash}.json`);
const stats = await fs.stat(filePath);
const now = Date.now();
// Check if cache has expired
if (now - stats.mtime.getTime() > this.ttl) {
await fs.unlink(filePath);
return null;
}
const data = await fs.readFile(filePath, 'utf-8');
const cached = JSON.parse(data);
return cached.value;
} catch (error) {
// Cache miss or error
return null;
}
}
/**
* Set value in cache
*/
async set(key, value) {
try {
const hash = this.hashKey(key);
const filePath = path.join(this.cachePath, `${hash}.json`);
// Ensure cache directory exists
await fs.mkdir(this.cachePath, { recursive: true });
const cacheData = {
key,
value,
timestamp: Date.now()
};
await fs.writeFile(filePath, JSON.stringify(cacheData, null, 2));
return true;
} catch (error) {
console.error('Cache write error:', error);
return false;
}
}
/**
* Delete value from cache
*/
async delete(key) {
try {
const hash = this.hashKey(key);
const filePath = path.join(this.cachePath, `${hash}.json`);
await fs.unlink(filePath);
return true;
} catch (error) {
return false;
}
}
/**
* Clear all cache entries
*/
async clear() {
try {
const files = await fs.readdir(this.cachePath);
const deletions = files
.filter(file => file.endsWith('.json'))
.map(file => fs.unlink(path.join(this.cachePath, file)));
await Promise.all(deletions);
return true;
} catch (error) {
return false;
}
}
/**
* Clean up expired cache entries
*/
async cleanup() {
try {
const files = await fs.readdir(this.cachePath);
const now = Date.now();
let cleaned = 0;
for (const file of files) {
if (!file.endsWith('.json')) continue;
const filePath = path.join(this.cachePath, file);
const stats = await fs.stat(filePath);
if (now - stats.mtime.getTime() > this.ttl) {
await fs.unlink(filePath);
cleaned++;
}
}
return { cleaned, total: files.length };
} catch (error) {
return { cleaned: 0, total: 0, error: error.message };
}
}
/**
* Get cache statistics
*/
async getStats() {
try {
const files = await fs.readdir(this.cachePath);
const jsonFiles = files.filter(file => file.endsWith('.json'));
const now = Date.now();
let totalSize = 0;
let expired = 0;
let valid = 0;
for (const file of jsonFiles) {
const filePath = path.join(this.cachePath, file);
const stats = await fs.stat(filePath);
totalSize += stats.size;
if (now - stats.mtime.getTime() > this.ttl) {
expired++;
} else {
valid++;
}
}
return {
total: jsonFiles.length,
valid,
expired,
totalSize: `${(totalSize / 1024).toFixed(2)} KB`,
cachePath: this.cachePath,
ttl: this.ttl / 1000 // Convert back to seconds
};
} catch (error) {
return {
error: error.message,
cachePath: this.cachePath
};
}
}
}