1import { ExpoMiddleware } from './ExpoMiddleware';
2import { ServerNext, ServerRequest, ServerResponse } from './server.types';
3import { getFaviconFromExpoConfigAsync } from '../../../export/favicon';
4
5const debug = require('debug')('expo:start:server:middleware:favicon') as typeof console.log;
6
7/**
8 * Middleware for generating a favicon.ico file for the current project if one doesn't exist.
9 *
10 * Test by making a get request with:
11 * curl -v http://localhost:8081/favicon.ico
12 */
13export class FaviconMiddleware extends ExpoMiddleware {
14  constructor(protected projectRoot: string) {
15    super(projectRoot, ['/favicon.ico']);
16  }
17
18  async handleRequestAsync(
19    req: ServerRequest,
20    res: ServerResponse,
21    next: ServerNext
22  ): Promise<void> {
23    if (!['GET', 'HEAD'].includes(req.method || '')) {
24      return next();
25    }
26
27    let faviconImageData: Buffer | null;
28    try {
29      const data = await getFaviconFromExpoConfigAsync(this.projectRoot);
30      if (!data) {
31        debug('No favicon defined in the Expo Config, skipping generation.');
32        return next();
33      }
34      faviconImageData = data.source;
35      debug('✅ Generated favicon successfully.');
36    } catch (error: any) {
37      debug('Failed to generate favicon from Expo config:', error);
38      return next(error);
39    }
40    // Respond with the generated favicon file
41    res.setHeader('Content-Type', 'image/x-icon');
42    res.end(faviconImageData);
43  }
44}
45