UNPKG

@stackmemoryai/stackmemory

Version:

Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a

116 lines (115 loc) 3.05 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); class DatabaseAdapter { projectId; config; constructor(projectId, config) { this.projectId = projectId; this.config = config || {}; } // Paginated table reads (for migration) async getTablePage(table, offset, limit) { void table; void offset; void limit; return []; } /** Returns the configured embedding provider, if any */ getEmbeddingProvider() { return void 0; } // Maintenance state (no-op defaults, overridden in SQLiteAdapter) async getMaintenanceState(_key) { return null; } async setMaintenanceState(_key, _value) { } // Garbage collection (no-op default, overridden in SQLiteAdapter) async runGC(_options) { return { framesDeleted: 0, eventsDeleted: 0, anchorsDeleted: 0, embeddingsDeleted: 0, ftsEntriesDeleted: 0 }; } // Retrieval logging (no-op defaults, overridden in SQLiteAdapter) async logRetrieval(_entry) { } async getRetrievalStats(_sinceDays) { return { totalQueries: 0, avgLatencyMs: 0, p95LatencyMs: 0, strategyDistribution: {}, avgResultsCount: 0, queriesWithNoResults: 0 }; } // Project registry (no-op defaults, overridden in SQLiteAdapter) async registerProject(_project) { } async getRegisteredProjects() { return []; } async setActiveProject(_projectId) { } async getActiveProject() { return null; } async removeProject(_projectId) { return false; } async touchProject(_projectId) { } // Utility methods generateId() { return crypto.randomUUID(); } sanitizeQuery(query) { console.warn( "sanitizeQuery() is deprecated and unsafe - use parameterized queries" ); return query.replace(/[;'"\\]/g, ""); } buildWhereClause(conditions) { const clauses = Object.entries(conditions).map(([key, value]) => { if (value === null) { return `${key} IS NULL`; } else if (Array.isArray(value)) { return `${key} IN (${value.map(() => "?").join(",")})`; } else { return `${key} = ?`; } }); return clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : ""; } buildOrderByClause(orderBy, direction) { if (!orderBy) return ""; const isSafe = /^[a-zA-Z0-9_.]+$/.test(orderBy); if (!isSafe) { return ""; } const dir = direction === "DESC" ? "DESC" : "ASC"; return ` ORDER BY ${orderBy} ${dir}`; } buildLimitClause(limit, offset) { if (!limit) return ""; let clause = ` LIMIT ${limit}`; if (offset) clause += ` OFFSET ${offset}`; return clause; } } class FeatureAwareDatabaseAdapter extends DatabaseAdapter { async canUseFeature(feature) { const features = this.getFeatures(); return features[feature] || false; } } export { DatabaseAdapter, FeatureAwareDatabaseAdapter };