import { logger } from '../logging.ts'; import type * as interfaces from '../../ts_interfaces/index.ts'; import type { StorageManager } from '../storage/index.ts'; const ACTIONLOG_PREFIX = '/actionlog/'; /** * Persists and queries action log entries via StorageManager. * Entries are stored as individual JSON files keyed by timestamp-id. */ export class ActionLog { private storageManager: StorageManager; constructor(storageManager: StorageManager) { this.storageManager = storageManager; } async append(entry: Omit): Promise { const full: interfaces.data.IActionLogEntry = { id: crypto.randomUUID(), timestamp: Date.now(), ...entry, }; const key = `${ACTIONLOG_PREFIX}${String(full.timestamp).padStart(16, '0')}-${full.id}.json`; await this.storageManager.setJSON(key, full); logger.debug(`Action logged: ${full.actionType} ${full.entityType} "${full.entityName}"`); return full; } async query(opts: { limit?: number; offset?: number; entityType?: interfaces.data.TActionEntity; } = {}): Promise<{ entries: interfaces.data.IActionLogEntry[]; total: number }> { const limit = opts.limit ?? 50; const offset = opts.offset ?? 0; const keys = await this.storageManager.list(ACTIONLOG_PREFIX); // Sort by key descending (newest first — keys are timestamp-prefixed) keys.sort((a, b) => b.localeCompare(a)); // Load all entries (or filter by entityType) let entries: interfaces.data.IActionLogEntry[] = []; for (const key of keys) { const entry = await this.storageManager.getJSON(key); if (entry) { if (opts.entityType && entry.entityType !== opts.entityType) continue; entries.push(entry); } } const total = entries.length; entries = entries.slice(offset, offset + limit); return { entries, total }; } }