UNPKG

loccon

Version:

A simple local context storage and management tool with CLI and web interfaces. Store, search, and organize code snippets, notes, and development contexts with sharded JSON storage.

195 lines 7.79 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StorageManager = void 0; const shardManager_1 = require("./shardManager"); const indexManager_1 = require("./indexManager"); const config_1 = require("./config"); const filelock_1 = require("../utils/filelock"); const validation_1 = require("../utils/validation"); const fuse_js_1 = __importDefault(require("fuse.js")); class StorageManager { constructor(storagePath) { this.storagePath = storagePath; this.shardManager = new shardManager_1.ShardManager(storagePath); this.indexManager = new indexManager_1.IndexManager(storagePath); this.lock = new filelock_1.FileLock(storagePath); } static async create(customStoragePath) { const storagePath = config_1.ConfigManager.getStoragePath(customStoragePath); await filelock_1.FileLock.cleanupStaleLocks(storagePath); await config_1.ConfigManager.initializeStorage(storagePath); return new StorageManager(storagePath); } async addContext(tag, content, categories = []) { validation_1.Validator.validateTag(tag); validation_1.Validator.validateContent(content); validation_1.Validator.validateCategories(categories); await this.lock.acquire(); try { // Check if tag already exists if (await this.indexManager.tagExists(tag)) { throw new Error(`Tag '${tag}' already exists`); } // Get current shard or create new one let currentShardId = await this.shardManager.getCurrentShard(); // Check if current shard has capacity const entry = { content: validation_1.Validator.sanitizeInput(content), metadata: { created: new Date().toISOString(), modified: new Date().toISOString(), categories: categories.map(cat => validation_1.Validator.sanitizeInput(cat)) } }; if (!(await this.shardManager.checkShardCapacity(currentShardId, JSON.stringify(entry)))) { currentShardId = await this.shardManager.createNewShard(); } // Load shard, add entry, and save const shardData = await this.shardManager.loadShard(currentShardId); shardData.contexts[tag] = entry; await this.shardManager.saveShard(shardData); // Update index await this.indexManager.setTagShard(tag, currentShardId); // Update last accessed time await config_1.ConfigManager.updateLastAccessed(this.storagePath); } finally { await this.lock.release(); } } async readContext(tag) { validation_1.Validator.validateTag(tag); const shardId = await this.indexManager.getShardForTag(tag); if (!shardId) { return null; } const shardData = await this.shardManager.loadShard(shardId); return shardData.contexts[tag] || null; } async updateContext(tag, content, categories = []) { validation_1.Validator.validateTag(tag); validation_1.Validator.validateContent(content); validation_1.Validator.validateCategories(categories); await this.lock.acquire(); try { const shardId = await this.indexManager.getShardForTag(tag); if (!shardId) { throw new Error(`Tag '${tag}' not found`); } const shardData = await this.shardManager.loadShard(shardId); const existingEntry = shardData.contexts[tag]; if (!existingEntry) { throw new Error(`Tag '${tag}' not found in shard`); } // Update the entry shardData.contexts[tag] = { content: validation_1.Validator.sanitizeInput(content), metadata: { created: existingEntry.metadata.created, modified: new Date().toISOString(), categories: categories.map(cat => validation_1.Validator.sanitizeInput(cat)) } }; await this.shardManager.saveShard(shardData); await config_1.ConfigManager.updateLastAccessed(this.storagePath); } finally { await this.lock.release(); } } async removeContext(tag) { validation_1.Validator.validateTag(tag); await this.lock.acquire(); try { const shardId = await this.indexManager.getShardForTag(tag); if (!shardId) { return false; } const shardData = await this.shardManager.loadShard(shardId); if (!(tag in shardData.contexts)) { return false; } delete shardData.contexts[tag]; await this.shardManager.saveShard(shardData); await this.indexManager.removeTag(tag); await config_1.ConfigManager.updateLastAccessed(this.storagePath); return true; } finally { await this.lock.release(); } } async listAllTags() { return await this.indexManager.getAllTags(); } async getAllContexts() { const allTags = await this.indexManager.getAllTags(); const contexts = {}; for (const tag of allTags) { const context = await this.readContext(tag); if (context) { contexts[tag] = context; } } return contexts; } async searchContexts(query, useFuzzy = false) { const allShardIds = await this.shardManager.getAllShardIds(); const allEntries = []; // Collect all entries from all shards for (const shardId of allShardIds) { const shardData = await this.shardManager.loadShard(shardId); for (const [tag, entry] of Object.entries(shardData.contexts)) { allEntries.push({ tag, entry }); } } if (useFuzzy) { // Use Fuse.js for fuzzy search const options = { includeScore: true, keys: [ { name: 'tag', weight: 0.4 }, { name: 'entry.content', weight: 0.4 }, { name: 'entry.metadata.categories', weight: 0.2 } ], threshold: 0.6 }; const fuse = new fuse_js_1.default(allEntries, options); const fuseResults = fuse.search(query); return fuseResults.map((result) => ({ tag: result.item.tag, entry: result.item.entry, score: result.score })); } else { // Simple text search const results = []; const queryLower = query.toLowerCase(); for (const { tag, entry } of allEntries) { const searchText = `${tag} ${entry.content} ${entry.metadata.categories.join(' ')}`.toLowerCase(); if (searchText.includes(queryLower)) { results.push({ tag, entry }); } } return results; } } async rebuildIndex() { await this.lock.acquire(); try { await this.indexManager.rebuildIndex(); } finally { await this.lock.release(); } } getStoragePath() { return this.storagePath; } } exports.StorageManager = StorageManager; //# sourceMappingURL=storage.js.map