- Add backup types and RecallBackup format - Create backup snapshot engine (createBackupSnapshot) - Add IndexedDB storage for local backups - Implement retention policy (max 10, 30-day cleanup) - Add backup validation and restore logic (merge/replace modes) - Add backup restore UI dialog with preview and confirmation - Add unsaved changes guard hook - Integrate backups section in Settings - Add backup endpoint to export-import API
76 lines
2.0 KiB
TypeScript
76 lines
2.0 KiB
TypeScript
import { RecallBackup } from '@/types/backup'
|
|
|
|
interface ValidationResult {
|
|
valid: boolean
|
|
errors: string[]
|
|
info?: {
|
|
noteCount: number
|
|
tagCount: number
|
|
createdAt: string
|
|
source: string
|
|
}
|
|
}
|
|
|
|
export function validateBackup(data: unknown): ValidationResult {
|
|
const errors: string[] = []
|
|
|
|
if (typeof data !== 'object' || data === null) {
|
|
return { valid: false, errors: ['Backup must be an object'] }
|
|
}
|
|
|
|
const backup = data as Record<string, unknown>
|
|
|
|
if (!validateSchemaVersion(backup as unknown as RecallBackup)) {
|
|
errors.push('Missing or invalid schemaVersion (expected "1.0")')
|
|
}
|
|
|
|
if (!backup.createdAt || typeof backup.createdAt !== 'string') {
|
|
errors.push('Missing or invalid createdAt field')
|
|
}
|
|
|
|
if (!backup.source || typeof backup.source !== 'string') {
|
|
errors.push('Missing or invalid source field')
|
|
}
|
|
|
|
if (!backup.metadata || typeof backup.metadata !== 'object') {
|
|
errors.push('Missing or invalid metadata field')
|
|
} else {
|
|
const metadata = backup.metadata as Record<string, unknown>
|
|
if (typeof metadata.noteCount !== 'number') {
|
|
errors.push('Missing or invalid metadata.noteCount')
|
|
}
|
|
if (typeof metadata.tagCount !== 'number') {
|
|
errors.push('Missing or invalid metadata.tagCount')
|
|
}
|
|
}
|
|
|
|
if (!backup.data || typeof backup.data !== 'object') {
|
|
errors.push('Missing or invalid data field')
|
|
} else {
|
|
const data = backup.data as Record<string, unknown>
|
|
if (!Array.isArray(data.notes)) {
|
|
errors.push('Missing or invalid data.notes (expected array)')
|
|
}
|
|
}
|
|
|
|
if (errors.length > 0) {
|
|
return { valid: false, errors }
|
|
}
|
|
|
|
const metadata = backup.metadata as { noteCount: number; tagCount: number }
|
|
return {
|
|
valid: true,
|
|
errors: [],
|
|
info: {
|
|
noteCount: metadata.noteCount,
|
|
tagCount: metadata.tagCount,
|
|
createdAt: backup.createdAt as string,
|
|
source: backup.source as string,
|
|
},
|
|
}
|
|
}
|
|
|
|
export function validateSchemaVersion(backup: RecallBackup): boolean {
|
|
return backup.schemaVersion === '1.0'
|
|
}
|