Split loader.ts (3163 LOC) into categories/ subdir (8 files, each <500 LOC): - access.ts (ACCESS_CONTROL + ADMISSION_CONTROL + ACCESS_AUTHORIZATION) - transfer-input.ts (TRANSFER_CONTROL + INPUT_CONTROL) - order-availability.ts (ORDER_CONTROL + AVAILABILITY) - separation-encryption.ts (SEPARATION incl. DL-* + ENCRYPTION) - pseudonymization.ts (PSEUDONYMIZATION) - resilience-recovery.ts (RESILIENCE + RECOVERY) - review.ts (REVIEW + training/TR-* controls) - category-map.ts (category metadata Map) Split controls-library.ts (943 LOC) into domain files: - transfer-audit.ts (TRANSFER + AUDIT) - deletion-incident.ts (DELETION + INCIDENT) - subprocessor-tom.ts (SUBPROCESSOR + TOM) - contract-data-subject.ts (CONTRACT + DATA_SUBJECT) - security-governance.ts (SECURITY + GOVERNANCE) Both barrel files preserved their full public API. No consumer imports changed. Zero new TypeScript errors introduced (305 pre-existing errors unchanged). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
247 lines
6.4 KiB
TypeScript
247 lines
6.4 KiB
TypeScript
// =============================================================================
|
|
// 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<string>()
|
|
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<ControlCategory, number> {
|
|
const counts = new Map<ControlCategory, number>()
|
|
getAllCategories().forEach((category) => {
|
|
counts.set(category, getControlsByCategory(category).length)
|
|
})
|
|
return counts
|
|
}
|