import { Injectable } from '@nestjs/common'; import type { HarnessSelection } from '@mosaicstack/types'; import type { ActorTenantScope } from '../auth/session-scope.js'; /** * TRANSITIONAL Slice-Zero selection store. * * This is an EXPLICITLY in-memory, owner-scoped store. It exists only so the * Slice-Zero HTTP surfaces round-trip a selection; it is NOT durable and does not * survive a process restart. Task Seven replaces it with the durable selection * repository backed by the database. * * The store is keyed STRICTLY by the server-derived scope (userId + tenantId). * There is no code path through which a client-supplied id chooses the key. */ @Injectable() export class HarnessSelectionRepository { private readonly byOwner = new Map(); get(scope: ActorTenantScope): HarnessSelection | null { return this.byOwner.get(ownerKey(scope)) ?? null; } set(scope: ActorTenantScope, selection: HarnessSelection): HarnessSelection { // Store a normalized copy of exactly the tuple fields — nothing else is retained. const stored: HarnessSelection = { harnessId: selection.harnessId, providerId: selection.providerId, modelId: selection.modelId, }; this.byOwner.set(ownerKey(scope), stored); return stored; } } /** Owner key from the server-derived scope only. NUL-separated to avoid collisions. */ function ownerKey(scope: ActorTenantScope): string { return `${scope.userId}${scope.tenantId}`; }