1import { ExpoConfig } from '@expo/config';
2import { Middleware } from 'metro-config';
3
4import { env } from '../env';
5import { DebugTool, getMetroDebugProperties } from './getMetroDebugProperties';
6import { logEventAsync } from './rudderstackClient';
7
8type Request = Parameters<Middleware>[0];
9type Response = Parameters<Middleware>[1];
10type Next = Parameters<Middleware>[2];
11
12/**
13 * Create a Metro middleware that reports when a debugger request was found.
14 * This will only be reported once, if the app uses Hermes and telemetry is not enabled.
15 */
16export function createDebuggerTelemetryMiddleware(
17  projectRoot: string,
18  exp: ExpoConfig
19): Middleware {
20  let hasReported = false;
21
22  // This only works for Hermes apps, disable when telemetry is turned off
23  if (env.EXPO_NO_TELEMETRY || exp.jsEngine !== 'hermes') {
24    return (req: Request, res: Response, next: Next) => {
25      if (typeof next === 'function') {
26        next(undefined);
27      }
28    };
29  }
30
31  return (req: Request, res: Response, next: Next) => {
32    // Only report once
33    if (hasReported && typeof next === 'function') {
34      return next(undefined);
35    }
36
37    const debugTool = findDebugTool(req);
38    if (debugTool) {
39      hasReported = true;
40      logEventAsync('metro debug', getMetroDebugProperties(projectRoot, exp, debugTool));
41    }
42
43    if (typeof next === 'function') {
44      return next(undefined);
45    }
46  };
47}
48
49/** Exposed for testing */
50export function findDebugTool(
51  req: Pick<Parameters<Middleware>[0], 'headers' | 'url'>
52): DebugTool | null {
53  if (req.headers['origin']?.includes('chrome-devtools')) {
54    return { name: 'chrome' };
55  }
56
57  if (req.url?.startsWith('/json')) {
58    const flipperUserAgent = req.headers['user-agent']?.match(/(Flipper)\/([^\s]+)/);
59    if (flipperUserAgent) {
60      return {
61        name: flipperUserAgent[1].toLowerCase(),
62        version: flipperUserAgent[2],
63      };
64    }
65  }
66
67  return null;
68}
69