Files split by agents before rate limit: - dsr/api.ts (669 → barrel + helpers) - einwilligungen/context.tsx (669 → barrel + hooks/reducer) - export.ts (753 → barrel + domain exporters) - incidents/api.ts (845 → barrel + api-helpers) - tom-generator/context.tsx (720 → barrel + hooks/reducer) - vendor-compliance/context.tsx (1010 → 234 provider + hooks/reducer) - api-docs/endpoints.ts — partially split (3 domain files created) - academy/api.ts — partially split (helpers extracted) - whistleblower/api.ts — partially split (helpers extracted) next build passes. api-client.ts (885) deferred to next session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
241 lines
7.4 KiB
TypeScript
241 lines
7.4 KiB
TypeScript
/**
|
|
* SDK ZIP Export
|
|
* Packages SDK state, documents, and a PDF report into a ZIP archive
|
|
*/
|
|
|
|
import JSZip from 'jszip'
|
|
import { SDKState, SDK_STEPS } from './types'
|
|
import { ExportOptions, DEFAULT_OPTIONS, formatDate, exportToPDF } from './export-pdf'
|
|
|
|
// =============================================================================
|
|
// ZIP EXPORT
|
|
// =============================================================================
|
|
|
|
export async function exportToZIP(state: SDKState, options: ExportOptions = {}): Promise<Blob> {
|
|
const opts = { ...DEFAULT_OPTIONS, ...options }
|
|
const zip = new JSZip()
|
|
|
|
const rootFolder = zip.folder('ai-compliance-sdk-export')
|
|
if (!rootFolder) throw new Error('Failed to create ZIP folder')
|
|
|
|
const phase1Folder = rootFolder.folder('phase1-assessment')
|
|
const phase2Folder = rootFolder.folder('phase2-documents')
|
|
const dataFolder = rootFolder.folder('data')
|
|
|
|
// Main State JSON
|
|
if (opts.includeRawData && dataFolder) {
|
|
dataFolder.file('state.json', JSON.stringify(state, null, 2))
|
|
}
|
|
|
|
// README
|
|
const readmeContent = `# AI Compliance SDK Export
|
|
|
|
Generated: ${formatDate(new Date())}
|
|
Tenant: ${state.tenantId}
|
|
Version: ${state.version}
|
|
|
|
## Folder Structure
|
|
|
|
- **phase1-assessment/**: Compliance Assessment Ergebnisse
|
|
- use-cases.json: Alle Use Cases
|
|
- risks.json: Identifizierte Risiken
|
|
- controls.json: Definierte Controls
|
|
- requirements.json: Compliance-Anforderungen
|
|
|
|
- **phase2-documents/**: Generierte Dokumente
|
|
- dsfa.json: Datenschutz-Folgenabschaetzung
|
|
- toms.json: Technische und organisatorische Massnahmen
|
|
- vvt.json: Verarbeitungsverzeichnis
|
|
- documents.json: Rechtliche Dokumente
|
|
|
|
- **data/**: Rohdaten
|
|
- state.json: Kompletter SDK State
|
|
|
|
## Progress
|
|
|
|
Phase 1: ${SDK_STEPS.filter(s => s.phase === 1 && state.completedSteps.includes(s.id)).length}/${SDK_STEPS.filter(s => s.phase === 1).length} completed
|
|
Phase 2: ${SDK_STEPS.filter(s => s.phase === 2 && state.completedSteps.includes(s.id)).length}/${SDK_STEPS.filter(s => s.phase === 2).length} completed
|
|
|
|
## Key Metrics
|
|
|
|
- Use Cases: ${state.useCases.length}
|
|
- Risks: ${state.risks.length}
|
|
- Controls: ${state.controls.length}
|
|
- Requirements: ${state.requirements.length}
|
|
- Evidence: ${state.evidence.length}
|
|
`
|
|
|
|
rootFolder.file('README.md', readmeContent)
|
|
|
|
// Phase 1 Files
|
|
if (phase1Folder) {
|
|
phase1Folder.file('use-cases.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.useCases.length,
|
|
useCases: state.useCases,
|
|
}, null, 2))
|
|
|
|
phase1Folder.file('risks.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.risks.length,
|
|
risks: state.risks,
|
|
summary: {
|
|
critical: state.risks.filter(r => r.severity === 'CRITICAL').length,
|
|
high: state.risks.filter(r => r.severity === 'HIGH').length,
|
|
medium: state.risks.filter(r => r.severity === 'MEDIUM').length,
|
|
low: state.risks.filter(r => r.severity === 'LOW').length,
|
|
},
|
|
}, null, 2))
|
|
|
|
phase1Folder.file('controls.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.controls.length,
|
|
controls: state.controls,
|
|
}, null, 2))
|
|
|
|
phase1Folder.file('requirements.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.requirements.length,
|
|
requirements: state.requirements,
|
|
}, null, 2))
|
|
|
|
phase1Folder.file('modules.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.modules.length,
|
|
modules: state.modules,
|
|
}, null, 2))
|
|
|
|
if (opts.includeEvidence) {
|
|
phase1Folder.file('evidence.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.evidence.length,
|
|
evidence: state.evidence,
|
|
}, null, 2))
|
|
}
|
|
|
|
phase1Folder.file('checkpoints.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
checkpoints: state.checkpoints,
|
|
}, null, 2))
|
|
|
|
if (state.screening) {
|
|
phase1Folder.file('screening.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
screening: state.screening,
|
|
}, null, 2))
|
|
}
|
|
}
|
|
|
|
// Phase 2 Files
|
|
if (phase2Folder) {
|
|
if (state.dsfa) {
|
|
phase2Folder.file('dsfa.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
dsfa: state.dsfa,
|
|
}, null, 2))
|
|
}
|
|
|
|
phase2Folder.file('toms.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.toms.length,
|
|
toms: state.toms,
|
|
}, null, 2))
|
|
|
|
phase2Folder.file('vvt.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.vvt.length,
|
|
processingActivities: state.vvt,
|
|
}, null, 2))
|
|
|
|
if (opts.includeDocuments) {
|
|
phase2Folder.file('documents.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.documents.length,
|
|
documents: state.documents,
|
|
}, null, 2))
|
|
}
|
|
|
|
if (state.cookieBanner) {
|
|
phase2Folder.file('cookie-banner.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
config: state.cookieBanner,
|
|
}, null, 2))
|
|
}
|
|
|
|
phase2Folder.file('retention-policies.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.retentionPolicies.length,
|
|
policies: state.retentionPolicies,
|
|
}, null, 2))
|
|
|
|
if (state.aiActClassification) {
|
|
phase2Folder.file('ai-act-classification.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
classification: state.aiActClassification,
|
|
}, null, 2))
|
|
}
|
|
|
|
phase2Folder.file('obligations.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.obligations.length,
|
|
obligations: state.obligations,
|
|
}, null, 2))
|
|
|
|
phase2Folder.file('consents.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.consents.length,
|
|
consents: state.consents,
|
|
}, null, 2))
|
|
|
|
if (state.dsrConfig) {
|
|
phase2Folder.file('dsr-config.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
config: state.dsrConfig,
|
|
}, null, 2))
|
|
}
|
|
|
|
phase2Folder.file('escalation-workflows.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.escalationWorkflows.length,
|
|
workflows: state.escalationWorkflows,
|
|
}, null, 2))
|
|
}
|
|
|
|
// Security Data
|
|
if (dataFolder) {
|
|
if (state.sbom) {
|
|
dataFolder.file('sbom.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
sbom: state.sbom,
|
|
}, null, 2))
|
|
}
|
|
|
|
if (state.securityIssues.length > 0) {
|
|
dataFolder.file('security-issues.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.securityIssues.length,
|
|
issues: state.securityIssues,
|
|
}, null, 2))
|
|
}
|
|
|
|
if (state.securityBacklog.length > 0) {
|
|
dataFolder.file('security-backlog.json', JSON.stringify({
|
|
exportedAt: new Date().toISOString(),
|
|
count: state.securityBacklog.length,
|
|
backlog: state.securityBacklog,
|
|
}, null, 2))
|
|
}
|
|
}
|
|
|
|
// Generate PDF and include in ZIP
|
|
try {
|
|
const pdfBlob = await exportToPDF(state, options)
|
|
const pdfArrayBuffer = await pdfBlob.arrayBuffer()
|
|
rootFolder.file('compliance-report.pdf', pdfArrayBuffer)
|
|
} catch (error) {
|
|
console.error('Failed to generate PDF for ZIP:', error)
|
|
}
|
|
|
|
return zip.generateAsync({ type: 'blob', compression: 'DEFLATE' })
|
|
}
|