1import { parse } from 'url';
2
3import { ServerRequest } from './server.types';
4import { CommandError } from '../../../utils/errors';
5
6const debug = require('debug')(
7  'expo:start:server:middleware:resolvePlatform'
8) as typeof console.log;
9
10/** Supported platforms */
11export type RuntimePlatform = 'ios' | 'android';
12
13/**
14 * Extract the runtime platform from the server request.
15 * 1. Query param `platform`: `?platform=ios`
16 * 2. Header `expo-platform`: `'expo-platform': ios`
17 * 3. Legacy header `exponent-platform`: `'exponent-platform': ios`
18 *
19 * Returns first item in the case of an array.
20 */
21export function parsePlatformHeader(req: ServerRequest): string | null {
22  const url = parse(req.url!, /* parseQueryString */ true);
23  const platform =
24    url.query?.platform || req.headers['expo-platform'] || req.headers['exponent-platform'];
25  return (Array.isArray(platform) ? platform[0] : platform) ?? null;
26}
27
28/** Guess the platform from the user-agent header. */
29export function resolvePlatformFromUserAgentHeader(req: ServerRequest): string | null {
30  let platform = null;
31  const userAgent = req.headers['user-agent'];
32  if (userAgent?.match(/Android/i)) {
33    platform = 'android';
34  }
35  if (userAgent?.match(/iPhone|iPad/i)) {
36    platform = 'ios';
37  }
38  debug(`Resolved platform ${platform} from user-agent header: ${userAgent}`);
39  return platform;
40}
41
42/** Assert if the runtime platform is not included. */
43export function assertMissingRuntimePlatform(platform?: any): asserts platform {
44  if (!platform) {
45    throw new CommandError(
46      'PLATFORM_HEADER',
47      `Must specify "expo-platform" header or "platform" query parameter`
48    );
49  }
50}
51
52/** Assert if the runtime platform is not correct. */
53export function assertRuntimePlatform(platform: string): asserts platform is RuntimePlatform {
54  const stringifiedPlatform = String(platform);
55  if (!['android', 'ios', 'web'].includes(stringifiedPlatform)) {
56    throw new CommandError(
57      'PLATFORM_HEADER',
58      `platform must be "android", "ios", or "web". Received: "${platform}"`
59    );
60  }
61}
62