import crypto from "node:crypto"; export class SessionRegistry { ttlMs; bindings = new Map(); constructor(ttlSeconds) { this.ttlMs = ttlSeconds * 1000; } upsert(context, sessionId) { const binding = { conversationId: context.conversationId, sessionId, lastUsedAt: Date.now(), }; this.bindings.set(this.makeKey(context), binding); return binding; } get(context) { const key = this.makeKey(context); const binding = this.bindings.get(key); if (!binding) { return null; } if (Date.now() - binding.lastUsedAt > this.ttlMs) { this.bindings.delete(key); return null; } binding.lastUsedAt = Date.now(); return binding; } count() { this.evictExpired(); return this.bindings.size; } evictExpired() { const expired = []; const now = Date.now(); for (const [key, binding] of this.bindings.entries()) { if (now - binding.lastUsedAt > this.ttlMs) { expired.push(binding.sessionId); this.bindings.delete(key); } } return expired; } makeKey(context) { const digest = crypto .createHash("sha256") .update([ context.conversationId, context.accessToken ?? "", context.projectId ?? "", ].join("|")) .digest("hex"); return digest; } }