1import { ExpoConfig } from '@expo/config';
2import os from 'os';
3import { URLSearchParams } from 'url';
4
5import { CommandError } from '../utils/errors';
6import { fetchAsync } from './rest/client';
7
8/** Create the expected session info. */
9export function createSessionInfo({
10  exp,
11  runtime,
12  url,
13}: {
14  exp: Pick<ExpoConfig, 'name' | 'description' | 'slug' | 'primaryColor'>;
15  runtime: 'native' | 'web';
16  url: string;
17}) {
18  return {
19    session: {
20      description: `${exp.name} on ${os.hostname()}`,
21      hostname: os.hostname(),
22      platform: runtime,
23      config: {
24        // TODO: if icons are specified, upload a url for them too so people can distinguish
25        description: exp.description,
26        name: exp.name,
27        slug: exp.slug,
28        primaryColor: exp.primaryColor,
29      },
30      url,
31      source: 'desktop',
32    },
33  };
34}
35
36/** Send a request to Expo API to keep the 'development session' alive for the provided devices. */
37export async function updateDevelopmentSessionAsync({
38  deviceIds,
39  exp,
40  runtime,
41  url,
42}: {
43  deviceIds: string[];
44  exp: Pick<ExpoConfig, 'name' | 'description' | 'slug' | 'primaryColor'>;
45  runtime: 'native' | 'web';
46  url: string;
47}) {
48  const searchParams = new URLSearchParams();
49  deviceIds.forEach((id) => {
50    searchParams.append('deviceId', id);
51  });
52
53  const results = await fetchAsync('development-sessions/notify-alive', {
54    searchParams,
55    method: 'POST',
56    body: JSON.stringify({
57      data: createSessionInfo({ exp, runtime, url }),
58    }),
59  });
60
61  if (!results.ok) {
62    throw new CommandError(
63      'API',
64      `Unexpected response when updating the development session on Expo servers: ${results.statusText}.`
65    );
66  }
67}
68