@@ -2,6 +2,35 @@ import JSZip from "jszip";
22
33import type { BackupMetadata , FullBackupData , MediaFile } from "../types" ;
44
5+ /**
6+ * Wrapper for data files with Homarr version
7+ */
8+ interface VersionedData < T > {
9+ homarrVersion : string ;
10+ data : T ;
11+ }
12+
13+ /**
14+ * Helper to wrap data with version
15+ */
16+ const wrapData = < T > ( homarrVersion : string , itemData : T ) : VersionedData < T > => ( {
17+ homarrVersion,
18+ data : itemData ,
19+ } ) ;
20+
21+ /**
22+ * Helper to unwrap data, supporting both versioned and legacy formats
23+ */
24+ const unwrapData = < T > ( content : string ) : T => {
25+ const parsed = JSON . parse ( content ) as Record < string , unknown > | VersionedData < unknown > ;
26+ // Check if data is in versioned format (has homarrVersion and data fields)
27+ if ( typeof parsed === "object" && "homarrVersion" in parsed && "data" in parsed ) {
28+ return ( parsed as VersionedData < T > ) . data ;
29+ }
30+ // Legacy format: return as-is
31+ return parsed as T ;
32+ } ;
33+
534/**
635 * Creates a ZIP archive buffer from backup data and media files
736 */
@@ -15,16 +44,16 @@ export const createZipArchiveAsync = async (
1544 // Add metadata
1645 zip . file ( "metadata.json" , JSON . stringify ( metadata , null , 2 ) ) ;
1746
18- // Add data files
19- zip . file ( "boards.json" , JSON . stringify ( data . boards , null , 2 ) ) ;
20- zip . file ( "integrations.json" , JSON . stringify ( data . integrations , null , 2 ) ) ;
21- zip . file ( "users.json" , JSON . stringify ( data . users , null , 2 ) ) ;
22- zip . file ( "groups.json" , JSON . stringify ( data . groups , null , 2 ) ) ;
23- zip . file ( "apps.json" , JSON . stringify ( data . apps , null , 2 ) ) ;
24- zip . file ( "searchEngines.json" , JSON . stringify ( data . searchEngines , null , 2 ) ) ;
47+ // Add data files with version wrapper
48+ zip . file ( "boards.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . boards ) , null , 2 ) ) ;
49+ zip . file ( "integrations.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . integrations ) , null , 2 ) ) ;
50+ zip . file ( "users.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . users ) , null , 2 ) ) ;
51+ zip . file ( "groups.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . groups ) , null , 2 ) ) ;
52+ zip . file ( "apps.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . apps ) , null , 2 ) ) ;
53+ zip . file ( "searchEngines.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . searchEngines ) , null , 2 ) ) ;
2554
2655 if ( data . settings ) {
27- zip . file ( "settings.json" , JSON . stringify ( data . settings , null , 2 ) ) ;
56+ zip . file ( "settings.json" , JSON . stringify ( wrapData ( metadata . homarrVersion , data . settings ) , null , 2 ) ) ;
2857 }
2958
3059 // Add media files to media folder
@@ -68,16 +97,16 @@ export const extractZipArchiveAsync = async (
6897 const searchEnginesFile = zip . file ( "searchEngines.json" ) ;
6998
7099 const data : FullBackupData = {
71- boards : boardsFile ? ( JSON . parse ( await boardsFile . async ( "string" ) ) as FullBackupData [ "boards" ] ) : [ ] ,
100+ boards : boardsFile ? unwrapData < FullBackupData [ "boards" ] > ( await boardsFile . async ( "string" ) ) : [ ] ,
72101 integrations : integrationsFile
73- ? ( JSON . parse ( await integrationsFile . async ( "string" ) ) as FullBackupData [ "integrations" ] )
102+ ? unwrapData < FullBackupData [ "integrations" ] > ( await integrationsFile . async ( "string" ) )
74103 : [ ] ,
75- users : usersFile ? ( JSON . parse ( await usersFile . async ( "string" ) ) as FullBackupData [ "users" ] ) : [ ] ,
76- groups : groupsFile ? ( JSON . parse ( await groupsFile . async ( "string" ) ) as FullBackupData [ "groups" ] ) : [ ] ,
77- apps : appsFile ? ( JSON . parse ( await appsFile . async ( "string" ) ) as FullBackupData [ "apps" ] ) : [ ] ,
78- settings : settingsFile ? ( JSON . parse ( await settingsFile . async ( "string" ) ) as FullBackupData [ "settings" ] ) : null ,
104+ users : usersFile ? unwrapData < FullBackupData [ "users" ] > ( await usersFile . async ( "string" ) ) : [ ] ,
105+ groups : groupsFile ? unwrapData < FullBackupData [ "groups" ] > ( await groupsFile . async ( "string" ) ) : [ ] ,
106+ apps : appsFile ? unwrapData < FullBackupData [ "apps" ] > ( await appsFile . async ( "string" ) ) : [ ] ,
107+ settings : settingsFile ? unwrapData < FullBackupData [ "settings" ] > ( await settingsFile . async ( "string" ) ) : null ,
79108 searchEngines : searchEnginesFile
80- ? ( JSON . parse ( await searchEnginesFile . async ( "string" ) ) as FullBackupData [ "searchEngines" ] )
109+ ? unwrapData < FullBackupData [ "searchEngines" ] > ( await searchEnginesFile . async ( "string" ) )
81110 : [ ] ,
82111 } ;
83112
0 commit comments