142637653SEvan Baconimport { ExpoMiddleware } from './ExpoMiddleware';
242637653SEvan Baconimport { ServerNext, ServerRequest, ServerResponse } from './server.types';
3*8a424bebSJames Ideimport { getFaviconFromExpoConfigAsync } from '../../../export/favicon';
442637653SEvan Bacon
542637653SEvan Baconconst debug = require('debug')('expo:start:server:middleware:favicon') as typeof console.log;
642637653SEvan Bacon
742637653SEvan Bacon/**
842637653SEvan Bacon * Middleware for generating a favicon.ico file for the current project if one doesn't exist.
942637653SEvan Bacon *
1042637653SEvan Bacon * Test by making a get request with:
1142637653SEvan Bacon * curl -v http://localhost:8081/favicon.ico
1242637653SEvan Bacon */
1342637653SEvan Baconexport class FaviconMiddleware extends ExpoMiddleware {
1442637653SEvan Bacon  constructor(protected projectRoot: string) {
1542637653SEvan Bacon    super(projectRoot, ['/favicon.ico']);
1642637653SEvan Bacon  }
1742637653SEvan Bacon
1842637653SEvan Bacon  async handleRequestAsync(
1942637653SEvan Bacon    req: ServerRequest,
2042637653SEvan Bacon    res: ServerResponse,
2142637653SEvan Bacon    next: ServerNext
2242637653SEvan Bacon  ): Promise<void> {
2342637653SEvan Bacon    if (!['GET', 'HEAD'].includes(req.method || '')) {
2442637653SEvan Bacon      return next();
2542637653SEvan Bacon    }
2642637653SEvan Bacon
2742637653SEvan Bacon    let faviconImageData: Buffer | null;
2842637653SEvan Bacon    try {
2942637653SEvan Bacon      const data = await getFaviconFromExpoConfigAsync(this.projectRoot);
3042637653SEvan Bacon      if (!data) {
3142637653SEvan Bacon        debug('No favicon defined in the Expo Config, skipping generation.');
3242637653SEvan Bacon        return next();
3342637653SEvan Bacon      }
3442637653SEvan Bacon      faviconImageData = data.source;
3542637653SEvan Bacon      debug('✅ Generated favicon successfully.');
3642637653SEvan Bacon    } catch (error: any) {
3742637653SEvan Bacon      debug('Failed to generate favicon from Expo config:', error);
3842637653SEvan Bacon      return next(error);
3942637653SEvan Bacon    }
4042637653SEvan Bacon    // Respond with the generated favicon file
4142637653SEvan Bacon    res.setHeader('Content-Type', 'image/x-icon');
4242637653SEvan Bacon    res.end(faviconImageData);
4342637653SEvan Bacon  }
4442637653SEvan Bacon}
45