// ============================================================================= // Control Library Loader // Barrel re-exporting all category controls and providing loader functions. // Data is split into categories/ subdirectory — each file <500 LOC. // ============================================================================= import { ControlLibraryEntry, ControlCategory, ControlApplicability, ConditionOperator, ReviewFrequency, ControlPriority, ControlComplexity, LocalizedString, FrameworkMapping, ApplicabilityCondition, } from '../types' import { CATEGORY_MAP } from './categories/category-map' import { ACCESS_CONTROLS } from './categories/access' import { TRANSFER_INPUT_CONTROLS } from './categories/transfer-input' import { ORDER_AVAILABILITY_CONTROLS } from './categories/order-availability' import { SEPARATION_ENCRYPTION_CONTROLS } from './categories/separation-encryption' import { PSEUDONYMIZATION_CONTROLS } from './categories/pseudonymization' import { RESILIENCE_RECOVERY_CONTROLS } from './categories/resilience-recovery' import { REVIEW_CONTROLS } from './categories/review' // Re-export raw types for consumers that import them from here export type { ControlLibraryEntry, ControlCategory, ControlApplicability, ConditionOperator, ReviewFrequency, ControlPriority, ControlComplexity, LocalizedString, FrameworkMapping, ApplicabilityCondition, } // ============================================================================= // PARSED CONTROL LIBRARY TYPE // ============================================================================= export interface ControlLibrary { metadata: { version: string lastUpdated: string totalControls: number } categories: Map< ControlCategory, { name: LocalizedString; gdprReference: string } > controls: ControlLibraryEntry[] } // ============================================================================= // ASSEMBLED CONTROL LIBRARY DATA // ============================================================================= const ALL_CONTROLS: ControlLibraryEntry[] = [ ...ACCESS_CONTROLS, ...TRANSFER_INPUT_CONTROLS, ...ORDER_AVAILABILITY_CONTROLS, ...SEPARATION_ENCRYPTION_CONTROLS, ...PSEUDONYMIZATION_CONTROLS, ...RESILIENCE_RECOVERY_CONTROLS, ...REVIEW_CONTROLS, ] const CONTROL_LIBRARY_DATA: ControlLibrary = { metadata: { version: '1.1.0', lastUpdated: '2026-03-19', totalControls: 88, }, categories: CATEGORY_MAP, controls: ALL_CONTROLS, } // ============================================================================= // LOADER FUNCTIONS // ============================================================================= let cachedLibrary: ControlLibrary | null = null /** * Get the control library (singleton with embedded data) */ export function getControlLibrary(): ControlLibrary { if (!cachedLibrary) { cachedLibrary = CONTROL_LIBRARY_DATA } return cachedLibrary } /** * Get all controls from the library */ export function getAllControls(): ControlLibraryEntry[] { return getControlLibrary().controls } /** * Get a control by ID */ export function getControlById(id: string): ControlLibraryEntry | undefined { return getAllControls().find((control) => control.id === id) } /** * Get controls by category */ export function getControlsByCategory( category: ControlCategory ): ControlLibraryEntry[] { return getAllControls().filter((control) => control.category === category) } /** * Get controls by type (TECHNICAL or ORGANIZATIONAL) */ export function getControlsByType( type: 'TECHNICAL' | 'ORGANIZATIONAL' ): ControlLibraryEntry[] { return getAllControls().filter((control) => control.type === type) } /** * Get controls by priority */ export function getControlsByPriority( priority: ControlPriority ): ControlLibraryEntry[] { return getAllControls().filter((control) => control.priority === priority) } /** * Get controls by tag */ export function getControlsByTag(tag: string): ControlLibraryEntry[] { return getAllControls().filter((control) => control.tags.includes(tag)) } /** * Get all unique tags from controls */ export function getAllTags(): string[] { const tags = new Set() getAllControls().forEach((control) => { control.tags.forEach((tag) => tags.add(tag)) }) return Array.from(tags).sort() } /** * Get category metadata */ export function getCategoryMetadata( category: ControlCategory ): { name: LocalizedString; gdprReference: string } | undefined { return getControlLibrary().categories.get(category) } /** * Get all categories */ export function getAllCategories(): ControlCategory[] { return Array.from(getControlLibrary().categories.keys()) } /** * Get categories with metadata (alias for API compatibility) */ export function getCategories(): Array<{ id: ControlCategory name: LocalizedString gdprReference: string }> { const library = getControlLibrary() const result: Array<{ id: ControlCategory; name: LocalizedString; gdprReference: string }> = [] library.categories.forEach((metadata, id) => { result.push({ id, name: metadata.name, gdprReference: metadata.gdprReference, }) }) return result } /** * Get library metadata */ export function getLibraryMetadata(): { version: string lastUpdated: string totalControls: number } { return getControlLibrary().metadata } /** * Search controls by text (searches name and description in both languages) */ export function searchControls( query: string, language: 'de' | 'en' = 'de' ): ControlLibraryEntry[] { const lowerQuery = query.toLowerCase() return getAllControls().filter((control) => { const name = control.name[language].toLowerCase() const description = control.description[language].toLowerCase() const code = control.code.toLowerCase() return ( name.includes(lowerQuery) || description.includes(lowerQuery) || code.includes(lowerQuery) ) }) } /** * Get controls by framework mapping */ export function getControlsByFramework( framework: string ): ControlLibraryEntry[] { return getAllControls().filter((control) => control.mappings.some((m) => m.framework === framework) ) } /** * Get controls count by category */ export function getControlsCountByCategory(): Map { const counts = new Map() getAllCategories().forEach((category) => { counts.set(category, getControlsByCategory(category).length) }) return counts }