/** * SDK State Management * * Reducer-based state management with persistence support */ import type { SDKState, SDKAction, UserPreferences, SDKPhase, SubscriptionTier, getStepById, } from '@breakpilot/compliance-sdk-types' // ============================================================================= // INITIAL STATE // ============================================================================= const initialPreferences: UserPreferences = { language: 'de', theme: 'light', compactMode: false, showHints: true, autoSave: true, autoValidate: true, } export const initialState: SDKState = { // Metadata version: '1.0.0', lastModified: new Date(), // Tenant & User tenantId: '', userId: '', subscription: 'PROFESSIONAL' as SubscriptionTier, // Progress currentPhase: 1 as SDKPhase, currentStep: 'use-case-workshop', completedSteps: [], checkpoints: {}, // Phase 1 Data useCases: [], activeUseCase: null, screening: null, modules: [], requirements: [], controls: [], evidence: [], checklist: [], risks: [], // Phase 2 Data aiActClassification: null, obligations: [], dsfa: null, toms: [], retentionPolicies: [], vvt: [], documents: [], cookieBanner: null, consents: [], dsrConfig: null, dsrRequests: [], escalationWorkflows: [], // Security sbom: null, securityIssues: [], securityBacklog: [], // UI State commandBarHistory: [], recentSearches: [], preferences: initialPreferences, } // ============================================================================= // REDUCER // ============================================================================= export function sdkReducer(state: SDKState, action: SDKAction): SDKState { const updateState = (updates: Partial): SDKState => ({ ...state, ...updates, lastModified: new Date(), }) switch (action.type) { case 'SET_STATE': return updateState(action.payload) case 'SET_CURRENT_STEP': { // Import dynamically to avoid circular dependencies const { getStepById } = require('@breakpilot/compliance-sdk-types') const step = getStepById(action.payload) return updateState({ currentStep: action.payload, currentPhase: step?.phase || state.currentPhase, }) } case 'COMPLETE_STEP': if (state.completedSteps.includes(action.payload)) { return state } return updateState({ completedSteps: [...state.completedSteps, action.payload], }) case 'SET_CHECKPOINT_STATUS': return updateState({ checkpoints: { ...state.checkpoints, [action.payload.id]: action.payload.status, }, }) // Use Cases case 'ADD_USE_CASE': return updateState({ useCases: [...state.useCases, action.payload], }) case 'UPDATE_USE_CASE': return updateState({ useCases: state.useCases.map(uc => uc.id === action.payload.id ? { ...uc, ...action.payload.data } : uc ), }) case 'DELETE_USE_CASE': return updateState({ useCases: state.useCases.filter(uc => uc.id !== action.payload), activeUseCase: state.activeUseCase === action.payload ? null : state.activeUseCase, }) case 'SET_ACTIVE_USE_CASE': return updateState({ activeUseCase: action.payload }) // Screening case 'SET_SCREENING': return updateState({ screening: action.payload }) // Modules case 'ADD_MODULE': return updateState({ modules: [...state.modules, action.payload], }) case 'UPDATE_MODULE': return updateState({ modules: state.modules.map(m => m.id === action.payload.id ? { ...m, ...action.payload.data } : m ), }) // Requirements case 'ADD_REQUIREMENT': return updateState({ requirements: [...state.requirements, action.payload], }) case 'UPDATE_REQUIREMENT': return updateState({ requirements: state.requirements.map(r => r.id === action.payload.id ? { ...r, ...action.payload.data } : r ), }) // Controls case 'ADD_CONTROL': return updateState({ controls: [...state.controls, action.payload], }) case 'UPDATE_CONTROL': return updateState({ controls: state.controls.map(c => c.id === action.payload.id ? { ...c, ...action.payload.data } : c ), }) // Evidence case 'ADD_EVIDENCE': return updateState({ evidence: [...state.evidence, action.payload], }) case 'UPDATE_EVIDENCE': return updateState({ evidence: state.evidence.map(e => e.id === action.payload.id ? { ...e, ...action.payload.data } : e ), }) case 'DELETE_EVIDENCE': return updateState({ evidence: state.evidence.filter(e => e.id !== action.payload), }) // Risks case 'ADD_RISK': return updateState({ risks: [...state.risks, action.payload], }) case 'UPDATE_RISK': return updateState({ risks: state.risks.map(r => r.id === action.payload.id ? { ...r, ...action.payload.data } : r ), }) case 'DELETE_RISK': return updateState({ risks: state.risks.filter(r => r.id !== action.payload), }) // AI Act case 'SET_AI_ACT_RESULT': return updateState({ aiActClassification: action.payload }) // Obligations case 'ADD_OBLIGATION': return updateState({ obligations: [...state.obligations, action.payload], }) case 'UPDATE_OBLIGATION': return updateState({ obligations: state.obligations.map(o => o.id === action.payload.id ? { ...o, ...action.payload.data } : o ), }) // DSFA case 'SET_DSFA': return updateState({ dsfa: action.payload }) // TOMs case 'ADD_TOM': return updateState({ toms: [...state.toms, action.payload], }) case 'UPDATE_TOM': return updateState({ toms: state.toms.map(t => t.id === action.payload.id ? { ...t, ...action.payload.data } : t ), }) // Retention Policies case 'ADD_RETENTION_POLICY': return updateState({ retentionPolicies: [...state.retentionPolicies, action.payload], }) case 'UPDATE_RETENTION_POLICY': return updateState({ retentionPolicies: state.retentionPolicies.map(p => p.id === action.payload.id ? { ...p, ...action.payload.data } : p ), }) // Processing Activities (VVT) case 'ADD_PROCESSING_ACTIVITY': return updateState({ vvt: [...state.vvt, action.payload], }) case 'UPDATE_PROCESSING_ACTIVITY': return updateState({ vvt: state.vvt.map(p => p.id === action.payload.id ? { ...p, ...action.payload.data } : p ), }) // Documents case 'ADD_DOCUMENT': return updateState({ documents: [...state.documents, action.payload], }) case 'UPDATE_DOCUMENT': return updateState({ documents: state.documents.map(d => d.id === action.payload.id ? { ...d, ...action.payload.data } : d ), }) // Cookie Banner case 'SET_COOKIE_BANNER': return updateState({ cookieBanner: action.payload }) // DSR case 'SET_DSR_CONFIG': return updateState({ dsrConfig: action.payload }) case 'ADD_DSR_REQUEST': return updateState({ dsrRequests: [...state.dsrRequests, action.payload], }) case 'UPDATE_DSR_REQUEST': return updateState({ dsrRequests: state.dsrRequests.map(r => r.id === action.payload.id ? { ...r, ...action.payload.data } : r ), }) // Escalation Workflows case 'ADD_ESCALATION_WORKFLOW': return updateState({ escalationWorkflows: [...state.escalationWorkflows, action.payload], }) case 'UPDATE_ESCALATION_WORKFLOW': return updateState({ escalationWorkflows: state.escalationWorkflows.map(w => w.id === action.payload.id ? { ...w, ...action.payload.data } : w ), }) // Security case 'ADD_SECURITY_ISSUE': return updateState({ securityIssues: [...state.securityIssues, action.payload], }) case 'UPDATE_SECURITY_ISSUE': return updateState({ securityIssues: state.securityIssues.map(i => i.id === action.payload.id ? { ...i, ...action.payload.data } : i ), }) case 'ADD_BACKLOG_ITEM': return updateState({ securityBacklog: [...state.securityBacklog, action.payload], }) case 'UPDATE_BACKLOG_ITEM': return updateState({ securityBacklog: state.securityBacklog.map(i => i.id === action.payload.id ? { ...i, ...action.payload.data } : i ), }) // UI State case 'ADD_COMMAND_HISTORY': return updateState({ commandBarHistory: [action.payload, ...state.commandBarHistory].slice(0, 50), }) case 'SET_PREFERENCES': return updateState({ preferences: { ...state.preferences, ...action.payload }, }) case 'RESET_STATE': return { ...initialState, lastModified: new Date() } default: return state } } // ============================================================================= // STORE // ============================================================================= export interface SDKStoreOptions { tenantId: string userId: string initialState?: Partial onChange?: (state: SDKState) => void } export interface SDKStore { getState: () => SDKState dispatch: (action: SDKAction) => void subscribe: (listener: (state: SDKState) => void) => () => void } export function createStore(options: SDKStoreOptions): SDKStore { let state: SDKState = { ...initialState, tenantId: options.tenantId, userId: options.userId, ...options.initialState, } const listeners = new Set<(state: SDKState) => void>() const getState = () => state const dispatch = (action: SDKAction) => { state = sdkReducer(state, action) listeners.forEach(listener => listener(state)) options.onChange?.(state) } const subscribe = (listener: (state: SDKState) => void) => { listeners.add(listener) return () => listeners.delete(listener) } return { getState, dispatch, subscribe } }