60 lines
2.6 KiB
TypeScript
60 lines
2.6 KiB
TypeScript
import { useSyncExternalStore } from 'react';
|
|
|
|
// Core-owned activation contract: engines consume it without depending on each other.
|
|
export const ENGINES = [
|
|
{ id: 'core', label: 'Core Engine', required: true },
|
|
{ id: 'context', label: 'Context Engine', required: false },
|
|
{ id: 'report', label: 'Report Engine', required: false },
|
|
{ id: 'remediation', label: 'Remediation Engine', required: false },
|
|
{ id: 'compliance', label: 'Compliance Engine', required: false }
|
|
] as const;
|
|
export type EngineId = typeof ENGINES[number]['id'];
|
|
export const ENGINE_PREFERENCES_KEY = 'ASSESSOR.engines.v1';
|
|
const defaults = Object.freeze({ core: true, context: true, report: true, remediation: true, compliance: true });
|
|
type Preferences = Readonly<Record<EngineId, boolean>>;
|
|
let snapshot: Preferences | undefined;
|
|
const listeners = new Set<() => void>();
|
|
|
|
export function readEnginePreferences(): Preferences {
|
|
if (snapshot) return snapshot;
|
|
try {
|
|
const saved = JSON.parse(window.localStorage.getItem(ENGINE_PREFERENCES_KEY) ?? '{}');
|
|
snapshot = Object.freeze({ core: true, context: saved?.context !== false, report: saved?.report !== false, remediation: saved?.remediation !== false,
|
|
compliance: saved?.compliance !== false });
|
|
} catch { snapshot = defaults; }
|
|
return snapshot;
|
|
}
|
|
|
|
export function setEngineEnabled(engine: EngineId, enabled: boolean): void {
|
|
if (engine === 'core') return;
|
|
const current = readEnginePreferences();
|
|
if (current[engine] === enabled) return;
|
|
snapshot = Object.freeze({ ...current, [engine]: enabled });
|
|
try { window.localStorage.setItem(ENGINE_PREFERENCES_KEY, JSON.stringify(snapshot)); }
|
|
catch { /* A blocked storage keeps the selection for this session. */ }
|
|
listeners.forEach(listener => listener());
|
|
}
|
|
|
|
function subscribe(listener: () => void) {
|
|
listeners.add(listener);
|
|
const changed = (event: StorageEvent) => {
|
|
if (event.key !== ENGINE_PREFERENCES_KEY && event.key !== null) return;
|
|
snapshot = undefined;
|
|
listener();
|
|
};
|
|
window.addEventListener('storage', changed);
|
|
return () => { listeners.delete(listener); window.removeEventListener('storage', changed); };
|
|
}
|
|
|
|
/** Calls the listener on every engine choice, including one made in another tab; returns the unsubscribe. */
|
|
export function subscribeEnginePreferences(listener: () => void): () => void {
|
|
return subscribe(listener);
|
|
}
|
|
|
|
export function useEnginePreferences(): Preferences {
|
|
return useSyncExternalStore(subscribe, readEnginePreferences, () => defaults);
|
|
}
|
|
|
|
/** Test support; call after unmounting consumers. */
|
|
export function resetEnginePreferencesForTests(): void { snapshot = undefined; }
|