@@ -364,6 +364,70 @@ class CodeInjector implements ICodeInjector {
364364 return [ lockHash , packages ] ;
365365 }
366366
367+ async allowBuildsFromWorkspaceFile ( dir : string , sourceName : string ) : Promise < { [ packageName : string ] : boolean } > {
368+ const content = await this . tryReadFile ( path . join ( dir , 'pnpm-workspace.yaml' ) ) ;
369+ if ( ! content ) {
370+ return { } ;
371+ }
372+
373+ let parsed : any = null ;
374+ try {
375+ parsed = yaml . parse ( content ) ;
376+ } catch ( e ) {
377+ afLogger . warn ( `Could not parse pnpm-workspace.yaml in ${ dir } , ignoring its allowBuilds: ${ e . message } ` ) ;
378+ return { } ;
379+ }
380+
381+ const allowBuilds : { [ packageName : string ] : boolean } = { } ;
382+ for ( const [ packageName , allowed ] of Object . entries ( parsed ?. allowBuilds || { } ) ) {
383+ if ( typeof allowed !== 'boolean' ) {
384+ afLogger . warn (
385+ `Ignoring allowBuilds."${ packageName } " declared by ${ sourceName } : expected true or false, got ${ JSON . stringify ( allowed ) } `
386+ ) ;
387+ continue ;
388+ }
389+ allowBuilds [ packageName ] = allowed ;
390+ }
391+ return allowBuilds ;
392+ }
393+
394+ async syncAllowBuildsToSpaTmp ( ) : Promise < { [ packageName : string ] : boolean } > {
395+ const sources : { name : string , dir : string } [ ] = [ ] ;
396+ const customComponentsDir = this . adminforth . config . customization ?. customComponentsDir ;
397+ if ( customComponentsDir ) {
398+ sources . push ( { name : 'customComponentsDir' , dir : path . resolve ( customComponentsDir ) } ) ;
399+ }
400+ for ( const plugin of this . adminforth . activatedPlugins ) {
401+ sources . push ( { name : plugin . constructor . name , dir : plugin . customFolderPath } ) ;
402+ }
403+
404+ const merged : { [ packageName : string ] : boolean } = { } ;
405+ for ( const { name, dir } of sources ) {
406+ const allowBuilds = await this . allowBuildsFromWorkspaceFile ( dir , name ) ;
407+ for ( const [ packageName , allowed ] of Object . entries ( allowBuilds ) ) {
408+ if ( merged [ packageName ] !== undefined && merged [ packageName ] !== allowed ) {
409+ afLogger . warn ( `Conflicting allowBuilds for "${ packageName } ", denying the build. Last source: ${ name } ` ) ;
410+ merged [ packageName ] = false ;
411+ continue ;
412+ }
413+ merged [ packageName ] = allowed ;
414+ }
415+ }
416+ process . env . HEAVY_DEBUG && console . log ( `🪲 allowBuilds collected from plugins/custom dir: ${ JSON . stringify ( merged ) } ` ) ;
417+
418+ if ( ! Object . keys ( merged ) . length ) {
419+ return merged ;
420+ }
421+
422+ const workspacePath = path . join ( this . spaTmpPath ( ) , 'pnpm-workspace.yaml' ) ;
423+ const workspaceContent = await this . tryReadFile ( workspacePath ) ;
424+ const workspace = workspaceContent ? ( yaml . parse ( workspaceContent ) || { } ) : { } ;
425+ workspace . allowBuilds = { ...merged , ...( workspace . allowBuilds || { } ) } ;
426+ await fs . promises . writeFile ( workspacePath , yaml . stringify ( workspace ) ) ;
427+
428+ return merged ;
429+ }
430+
367431 getSpaDir ( ) {
368432 let spaDir = path . join ( ADMIN_FORTH_ABSOLUTE_PATH , 'spa' ) ;
369433 if ( ! fs . existsSync ( spaDir ) ) {
@@ -838,6 +902,8 @@ class CodeInjector implements ICodeInjector {
838902
839903 const iconPackagesNamesHash = hashify ( iconPackageNames ) ;
840904
905+ await this . syncAllowBuildsToSpaTmp ( ) ;
906+
841907 const fullHash = `spa>${ spaLockHash } ::icons>${ iconPackagesNamesHash } ::user/custom>${ usersLockHash } ::${ pluginsLockHash } ` ;
842908 const hashPath = path . join ( this . spaTmpPath ( ) , 'node_modules' , '.adminforth_hash' ) ;
843909
0 commit comments