@@ -473,10 +473,11 @@ router.put('/', async (req, res) => {
473473 }
474474
475475 const { pluginJson, icon, readme, changelogs } = await exploreZip ( pluginZip . data ) ;
476- const errorMessage = validatePlugin ( pluginJson , icon , readme ) ;
477-
478- if ( errorMessage ) {
479- res . status ( 400 ) . send ( { error : errorMessage } ) ;
476+
477+ try {
478+ validatePlugin ( pluginJson , icon , readme ) ;
479+ } catch ( error ) {
480+ res . status ( 400 ) . send ( { error : error . message } ) ;
480481 return ;
481482 }
482483
@@ -637,11 +638,54 @@ router.delete('/:id', async (req, res) => {
637638} ) ;
638639
639640async function exploreZip ( file ) {
640- const zip = await jsZip . loadAsync ( file ) ;
641- const pluginJson = JSON . parse ( await zip . file ( 'plugin.json' ) ?. async ( 'string' ) ) ;
642- const icon = await zip . file ( 'icon.png' ) ?. async ( 'base64' ) ;
643- const readme = await zip . file ( 'readme.md' ) ?. async ( 'string' ) ;
644- const changelogs = await zip . file ( pluginJson . changelogs || 'changelogs.md' ) ?. async ( 'string' ) ;
641+ // Create a new JSZip instance for each request to avoid caching issues
642+ const zip = new JSZip ( ) ;
643+ await zip . loadAsync ( file ) ;
644+
645+ const pluginJsonFile = zip . file ( 'plugin.json' ) ;
646+ if ( ! pluginJsonFile ) {
647+ throw new Error ( 'Missing plugin.json file in the zip.' ) ;
648+ }
649+ const pluginJson = JSON . parse ( await pluginJsonFile . async ( 'string' ) ) ;
650+
651+ const iconPath = pluginJson . icon || 'icon.png' ;
652+ const iconFile = zip . file ( iconPath ) ;
653+ let icon = null ;
654+ if ( iconFile ) {
655+ icon = await iconFile . async ( 'base64' ) ;
656+ } else if ( iconPath !== 'icon.png' ) {
657+ // If custom path failed, try the default path
658+ const defaultIconFile = zip . file ( 'icon.png' ) ;
659+ if ( defaultIconFile ) {
660+ icon = await defaultIconFile . async ( 'base64' ) ;
661+ }
662+ }
663+
664+ const readmePath = pluginJson . readme || 'readme.md' ;
665+ let readmeFile = zip . file ( readmePath ) ;
666+ if ( ! readmeFile && readmePath !== 'readme.md' ) {
667+ // If custom path failed, try the default path
668+ readmeFile = zip . file ( 'readme.md' ) ;
669+ }
670+
671+ let readme = null ;
672+ if ( readmeFile ) {
673+ const readmeContent = await readmeFile . async ( 'string' ) ;
674+ readme = readmeContent && readmeContent . trim ( ) ? readmeContent . trim ( ) : null ;
675+ }
676+
677+ const changelogsPath = pluginJson . changelogs || 'changelogs.md' ;
678+ let changelogsFile = zip . file ( changelogsPath ) ;
679+ if ( ! changelogsFile && changelogsPath !== 'changelogs.md' ) {
680+ // If custom path failed, try the default path
681+ changelogsFile = zip . file ( 'changelogs.md' ) ;
682+ }
683+
684+ let changelogs = null ;
685+ if ( changelogsFile ) {
686+ const changelogsContent = await changelogsFile . async ( 'string' ) ;
687+ changelogs = changelogsContent && changelogsContent . trim ( ) ? changelogsContent . trim ( ) : null ;
688+ }
645689
646690 return { pluginJson, icon, readme, changelogs } ;
647691}
@@ -676,7 +720,10 @@ function validatePlugin(json, icon, readmeFile) {
676720 throw new Error ( 'Invalid version number, version should be in the format <major>.<minor>.<patch> (e.g. 0.0.1)' ) ;
677721 }
678722
679- const missingFields = [ name , version , id , main ] . filter ( ( field ) => ! field ) ;
723+ const requiredFields = { name, version, id, main } ;
724+ const missingFields = Object . entries ( requiredFields )
725+ . filter ( ( [ _ , value ] ) => ! value )
726+ . map ( ( [ key ] ) => key ) ;
680727 if ( missingFields . length ) {
681728 throw new Error ( `Missing fields in plugin.json: ${ missingFields . join ( ', ' ) } ` ) ;
682729 }
0 commit comments