@rnx-kit/cli 0.16.13 → 0.16.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/coverage/clover.xml +2 -2
  3. package/coverage/lcov-report/index.html +1 -1
  4. package/coverage/lcov-report/src/bundle/defaultPlugins.ts.html +1 -1
  5. package/coverage/lcov-report/src/bundle/index.html +1 -1
  6. package/coverage/lcov-report/src/bundle/kit-config.ts.html +1 -1
  7. package/coverage/lcov-report/src/bundle/metro.ts.html +1 -1
  8. package/coverage/lcov-report/src/bundle/overrides.ts.html +1 -1
  9. package/coverage/lcov-report/src/copy-assets.ts.html +1 -1
  10. package/coverage/lcov-report/src/index.html +1 -1
  11. package/coverage/lcov-report/src/metro-config.ts.html +1 -1
  12. package/coverage/lcov-report/src/test.ts.html +1 -1
  13. package/lib/bundle.d.ts +1 -1
  14. package/lib/bundle.d.ts.map +1 -1
  15. package/lib/bundle.js.map +1 -1
  16. package/lib/clean.d.ts.map +1 -1
  17. package/lib/clean.js.map +1 -1
  18. package/lib/ram-bundle.d.ts +1 -1
  19. package/lib/ram-bundle.d.ts.map +1 -1
  20. package/lib/ram-bundle.js.map +1 -1
  21. package/lib/serve/external.d.ts +4 -0
  22. package/lib/serve/external.d.ts.map +1 -0
  23. package/lib/serve/external.js +29 -0
  24. package/lib/serve/external.js.map +1 -0
  25. package/lib/serve/help.d.ts +7 -0
  26. package/lib/serve/help.d.ts.map +1 -0
  27. package/lib/serve/help.js +50 -0
  28. package/lib/serve/help.js.map +1 -0
  29. package/lib/serve/keyboard.d.ts +11 -0
  30. package/lib/serve/keyboard.d.ts.map +1 -0
  31. package/lib/serve/keyboard.js +64 -0
  32. package/lib/serve/keyboard.js.map +1 -0
  33. package/lib/serve/types.d.ts +76 -0
  34. package/lib/serve/types.d.ts.map +1 -0
  35. package/lib/serve/types.js +3 -0
  36. package/lib/serve/types.js.map +1 -0
  37. package/lib/start.d.ts +3 -19
  38. package/lib/start.d.ts.map +1 -1
  39. package/lib/start.js +103 -156
  40. package/lib/start.js.map +1 -1
  41. package/lib/write-third-party-notices.d.ts +1 -1
  42. package/lib/write-third-party-notices.d.ts.map +1 -1
  43. package/lib/write-third-party-notices.js.map +1 -1
  44. package/package.json +17 -13
  45. package/src/bundle.ts +1 -1
  46. package/src/clean.ts +1 -3
  47. package/src/ram-bundle.ts +1 -1
  48. package/src/serve/external.ts +50 -0
  49. package/src/serve/help.ts +60 -0
  50. package/src/serve/keyboard.ts +76 -0
  51. package/src/serve/types.ts +86 -0
  52. package/src/start.ts +138 -222
  53. package/src/write-third-party-notices.ts +1 -1
@@ -0,0 +1,76 @@
1
+ import { info } from "@rnx-kit/console";
2
+ import type { MetroTerminal } from "@rnx-kit/metro-service";
3
+ import nodeFetch from "node-fetch";
4
+ import qrcode from "qrcode";
5
+ import readline from "readline";
6
+ import type { DevServerMiddleware } from "./types";
7
+
8
+ type Options = {
9
+ devServerUrl: string;
10
+ help: () => void;
11
+ messageSocketEndpoint: DevServerMiddleware["messageSocketEndpoint"];
12
+ terminal: MetroTerminal["terminal"];
13
+ };
14
+
15
+ export function attachKeyHandlers({
16
+ devServerUrl,
17
+ help,
18
+ messageSocketEndpoint,
19
+ terminal,
20
+ }: Options) {
21
+ process.stdin.setRawMode(true);
22
+ process.stdin.on("keypress", (_key, data) => {
23
+ const { ctrl, name } = data;
24
+ if (ctrl === true) {
25
+ switch (name) {
26
+ case "c":
27
+ info("Exiting...");
28
+ process.exit();
29
+ break;
30
+ case "z":
31
+ process.emit("SIGTSTP", "SIGTSTP");
32
+ break;
33
+ }
34
+ } else {
35
+ switch (name) {
36
+ case "d":
37
+ info("Opening developer menu...");
38
+ messageSocketEndpoint.broadcast("devMenu", undefined);
39
+ break;
40
+
41
+ case "h":
42
+ help();
43
+ break;
44
+
45
+ case "j": {
46
+ info("Opening debugger...");
47
+ // TODO: Remove `node-fetch` when we drop support for Node 16
48
+ const ftch = "fetch" in globalThis ? fetch : nodeFetch;
49
+ ftch(devServerUrl + "/open-debugger", { method: "POST" });
50
+ break;
51
+ }
52
+
53
+ case "q": {
54
+ const url = `${devServerUrl}/index.bundle`;
55
+ qrcode.toString(url, { type: "terminal" }, (_err, qr) => {
56
+ terminal.log("");
57
+ terminal.log(url + ":");
58
+ terminal.log(qr);
59
+ });
60
+ break;
61
+ }
62
+
63
+ case "r":
64
+ info("Reloading app...");
65
+ messageSocketEndpoint.broadcast("reload", undefined);
66
+ break;
67
+
68
+ case "return":
69
+ terminal.log("");
70
+ break;
71
+ }
72
+ }
73
+ });
74
+
75
+ readline.emitKeypressEvents(process.stdin);
76
+ }
@@ -0,0 +1,86 @@
1
+ import type * as logger from "@rnx-kit/console";
2
+ import type { Server as Middleware } from "connect";
3
+ import type { Server as HttpServer } from "http";
4
+ import type { Server as HttpsServer } from "https";
5
+ import type { RunServerOptions } from "metro";
6
+
7
+ // https://github.com/react-native-community/cli/blob/11.x/packages/cli-server-api/src/index.ts#L32
8
+ type MiddlewareOptions = {
9
+ host?: string;
10
+ watchFolders: readonly string[];
11
+ port: number;
12
+ };
13
+
14
+ type WebSocketServer = Required<RunServerOptions>["websocketEndpoints"][string];
15
+
16
+ export type DevServerMiddleware = {
17
+ websocketEndpoints: RunServerOptions["websocketEndpoints"];
18
+ debuggerProxyEndpoint: {
19
+ server: WebSocketServer;
20
+ isDebuggerConnected: () => boolean;
21
+ };
22
+ messageSocketEndpoint: {
23
+ server: WebSocketServer;
24
+ broadcast: (method: string, params?: Record<string, unknown>) => void;
25
+ };
26
+ eventsSocketEndpoint: {
27
+ server: WebSocketServer;
28
+ reportEvent: (event: unknown) => void;
29
+ };
30
+ middleware: Middleware;
31
+ };
32
+
33
+ export type DevServerMiddleware6 = Pick<DevServerMiddleware, "middleware"> & {
34
+ attachToServer: (server: HttpServer | HttpsServer) => {
35
+ debuggerProxy: DevServerMiddleware["debuggerProxyEndpoint"];
36
+ eventsSocket: DevServerMiddleware["eventsSocketEndpoint"];
37
+ messageSocket: DevServerMiddleware["messageSocketEndpoint"];
38
+ };
39
+ };
40
+
41
+ /** `@react-native-community/cli-server-api` */
42
+ export type CliServerApi = {
43
+ createDevServerMiddleware: (
44
+ options: MiddlewareOptions
45
+ ) => DevServerMiddleware | DevServerMiddleware6;
46
+ indexPageMiddleware: Middleware;
47
+ };
48
+
49
+ // https://github.com/facebook/react-native/blob/d208dc422c9239d126e0da674451c5898d57319d/packages/community-cli-plugin/src/commands/start/runServer.js#L32
50
+ export type StartCommandArgs = {
51
+ assetPlugins?: string[];
52
+ cert?: string;
53
+ customLogReporterPath?: string;
54
+ host?: string;
55
+ https?: boolean;
56
+ maxWorkers?: number;
57
+ key?: string;
58
+ platforms?: string[];
59
+ port?: number;
60
+ resetCache?: boolean;
61
+ sourceExts?: string[];
62
+ transformer?: string;
63
+ watchFolders?: string[];
64
+ config?: string;
65
+ projectRoot?: string;
66
+ interactive: boolean;
67
+ };
68
+
69
+ // https://github.com/facebook/react-native/blob/3e7a873f2d1c5170a7f4c88064897e74a149c5d5/packages/dev-middleware/src/createDevMiddleware.js#L40
70
+ type DevMiddlewareAPI = {
71
+ middleware: Middleware;
72
+ websocketEndpoints: RunServerOptions["websocketEndpoints"];
73
+ };
74
+
75
+ type DevMiddlewareOptions = {
76
+ projectRoot: string;
77
+ logger?: typeof logger;
78
+ unstable_browserLauncher?: unknown;
79
+ unstable_eventReporter?: unknown;
80
+ unstable_experiments?: unknown;
81
+ };
82
+
83
+ /** `@react-native/dev-middleware` */
84
+ export type CoreDevMiddleware = {
85
+ createDevMiddleware: (options: DevMiddlewareOptions) => DevMiddlewareAPI;
86
+ };
package/src/start.ts CHANGED
@@ -1,67 +1,25 @@
1
- import type CliServerApi from "@react-native-community/cli-server-api";
2
- import type { Config as CLIConfig } from "@react-native-community/cli-types";
3
- import type { MetroTerminal } from "@rnx-kit/metro-service";
1
+ import type { Config } from "@react-native-community/cli-types";
2
+ import * as logger from "@rnx-kit/console";
4
3
  import {
5
4
  createTerminal,
5
+ isDevServerRunning,
6
6
  loadMetroConfig,
7
7
  startServer,
8
8
  } from "@rnx-kit/metro-service";
9
- import chalk from "chalk";
10
- import type { Server as HttpServer } from "http";
11
- import type { Server as HttpsServer } from "https";
12
9
  import type { ReportableEvent, Reporter, RunServerOptions } from "metro";
13
10
  import type { Middleware } from "metro-config";
14
11
  import type Server from "metro/src/Server";
15
- import * as os from "os";
16
12
  import * as path from "path";
17
- import qrcode from "qrcode";
18
- import readline from "readline";
19
13
  import { customizeMetroConfig } from "./metro-config";
14
+ import { requireExternal } from "./serve/external";
15
+ import { makeHelp } from "./serve/help";
16
+ import { attachKeyHandlers } from "./serve/keyboard";
20
17
  import { getKitServerConfig } from "./serve/kit-config";
21
-
22
- type DevServerMiddleware = ReturnType<
23
- (typeof CliServerApi)["createDevServerMiddleware"]
24
- >;
25
-
26
- type DevServerMiddleware6 = Pick<DevServerMiddleware, "middleware"> & {
27
- attachToServer: (server: HttpServer | HttpsServer) => {
28
- debuggerProxy: DevServerMiddleware["debuggerProxyEndpoint"];
29
- eventsSocket: DevServerMiddleware["eventsSocketEndpoint"];
30
- messageSocket: DevServerMiddleware["messageSocketEndpoint"];
31
- };
32
- };
33
-
34
- export type CLIStartOptions = {
35
- port: number;
36
- host: string;
37
- projectRoot?: string;
38
- watchFolders?: string[];
39
- assetPlugins?: string[];
40
- sourceExts?: string[];
41
- maxWorkers?: number;
42
- resetCache?: boolean;
43
- customLogReporterPath?: string;
44
- https?: boolean;
45
- key?: string;
46
- cert?: string;
47
- config?: string;
48
- interactive: boolean;
49
- id?: string;
50
- };
51
-
52
- function friendlyRequire<T>(...modules: string[]): T {
53
- try {
54
- const modulePath = modules.reduce((startDir, module) => {
55
- return require.resolve(module, { paths: [startDir] });
56
- }, process.cwd());
57
- return require(modulePath) as T;
58
- } catch (_) {
59
- const module = modules[modules.length - 1];
60
- throw new Error(
61
- `Cannot find module '${module}'. This probably means that '@rnx-kit/cli' is not compatible with the version of '@react-native-community/cli' that you are currently using. Please update to the latest version and try again. If the issue still persists after the update, please file a bug at https://github.com/microsoft/rnx-kit/issues.`
62
- );
63
- }
64
- }
18
+ import type {
19
+ DevServerMiddleware,
20
+ DevServerMiddleware6,
21
+ StartCommandArgs,
22
+ } from "./serve/types";
65
23
 
66
24
  function hasAttachToServerFunction(
67
25
  devServer: DevServerMiddleware | DevServerMiddleware6
@@ -69,111 +27,32 @@ function hasAttachToServerFunction(
69
27
  return "attachToServer" in devServer;
70
28
  }
71
29
 
72
- function makeHelp(terminal: MetroTerminal["terminal"]): () => void {
73
- const menuItems: ("" | [string, string])[] = [
74
- ["R", "Reload the app"],
75
- ["D", "Open developer menu"],
76
- ["A", "Show bundler address QR code"],
77
- "",
78
- ["H", "Show this help message"],
79
- ["Ctrl-C", "Quit"],
80
- ];
81
-
82
- const margin = 4;
83
- const maxColumnWidth = (index: number) => {
84
- return (max: number, item: (typeof menuItems)[number]) => {
85
- if (!item) {
86
- return max;
87
- }
88
-
89
- const width = item[index].length;
90
- return width > max ? width : max;
91
- };
92
- };
93
-
94
- const keyWidth = menuItems.reduce(maxColumnWidth(0), 0);
95
- const labelWidth = menuItems.reduce(maxColumnWidth(1), 0);
96
- const separator = `┠${"─".repeat(labelWidth + keyWidth + margin + 1)}`;
97
-
98
- const dim = chalk.dim;
99
- const lines = menuItems.map((item) => {
100
- if (!item) {
101
- return separator;
102
- }
103
-
104
- const [key, label] = item;
105
- const labelPadding = labelWidth - label.length;
106
- const keyPadding = keyWidth - key.length;
107
- const padding = " ".repeat(labelPadding + keyPadding + margin);
108
- return `┃ ${dim(label)}${padding}${key}`;
109
- });
110
-
111
- return () => {
112
- for (const line of lines) {
113
- terminal.log(line);
114
- }
115
- terminal.log("");
116
- };
117
- }
118
-
119
30
  export async function rnxStart(
120
- _argv: Array<string>,
121
- cliConfig: CLIConfig,
122
- cliOptions: CLIStartOptions
31
+ _argv: string[],
32
+ ctx: Config,
33
+ args: StartCommandArgs
123
34
  ): Promise<void> {
124
- const serverConfig = getKitServerConfig(cliOptions);
35
+ const serverConfig = getKitServerConfig(args);
125
36
 
126
- const { createDevServerMiddleware, indexPageMiddleware } = friendlyRequire<
127
- typeof CliServerApi
128
- >(
129
- "react-native",
130
- "@react-native-community/cli",
37
+ const { createDevServerMiddleware, indexPageMiddleware } = requireExternal(
131
38
  "@react-native-community/cli-server-api"
132
39
  );
133
40
 
134
41
  // interactive mode requires raw access to stdin
135
- let interactive = cliOptions.interactive;
42
+ let interactive = args.interactive;
136
43
  if (interactive) {
137
44
  interactive = process.stdin.isTTY;
138
45
  if (!interactive) {
139
- console.warn(
140
- chalk.yellow(
141
- "Warning: Interactive mode is not supported on this terminal"
142
- )
143
- );
46
+ logger.warn("Interactive mode is not supported in this environment");
144
47
  }
145
48
  }
146
49
 
147
- // create a Metro terminal and reporter for writing to the console
148
- const { terminal, reporter: terminalReporter } = createTerminal(
149
- cliOptions.customLogReporterPath
150
- );
151
-
152
- const printHelp = makeHelp(terminal);
153
-
154
- // create a reporter function, to be bound to the Metro configuration.
155
- // which writes to the Metro terminal and
156
- // also notifies the `reportEvent` delegate.
157
- let reportEventDelegate: Reporter["update"] | undefined = undefined;
158
- const reporter: Reporter = {
159
- update(event: ReportableEvent) {
160
- terminalReporter.update(event);
161
- if (reportEventDelegate) {
162
- reportEventDelegate(event);
163
- }
164
- if (interactive && event.type === "dep_graph_loading") {
165
- printHelp();
166
- }
167
- },
168
- };
169
-
170
50
  // load Metro configuration, applying overrides from the command line
171
- const metroConfig = await loadMetroConfig(cliConfig, {
172
- ...cliOptions,
51
+ const metroConfig = await loadMetroConfig(ctx, {
52
+ ...args,
173
53
  ...(serverConfig.projectRoot
174
54
  ? { projectRoot: path.resolve(serverConfig.projectRoot) }
175
55
  : undefined),
176
- reporter,
177
56
  ...(serverConfig.sourceExts
178
57
  ? { sourceExts: serverConfig.sourceExts }
179
58
  : undefined),
@@ -186,39 +65,89 @@ export async function rnxStart(
186
65
  : undefined),
187
66
  });
188
67
 
68
+ // create a Metro terminal and reporter for writing to the console
69
+ const { terminal, reporter: terminalReporter } = createTerminal(
70
+ args.customLogReporterPath
71
+ );
72
+
189
73
  // customize the metro config to include plugins, presets, etc.
190
- customizeMetroConfig(metroConfig, serverConfig, (message: string): void => {
191
- terminal.log(message);
192
- });
74
+ const log = (message: string): void => terminal.log(message);
75
+ customizeMetroConfig(metroConfig, serverConfig, log);
76
+
77
+ const {
78
+ projectRoot,
79
+ server: { port },
80
+ watchFolders,
81
+ } = metroConfig;
82
+ const scheme = args.https === true ? "https" : "http";
83
+ const serverStatus = await isDevServerRunning(
84
+ scheme,
85
+ args.host,
86
+ port,
87
+ projectRoot
88
+ );
89
+
90
+ switch (serverStatus) {
91
+ case "already_running":
92
+ logger.info(
93
+ `A dev server is already running for this project on port ${port}. ` +
94
+ "Exiting..."
95
+ );
96
+ return;
97
+ case "in_use":
98
+ logger.error(
99
+ `Another process is using port ${port}. Please terminate this ` +
100
+ "process and try again, or try another port with `--port`."
101
+ );
102
+ return;
103
+ }
193
104
 
194
105
  // create middleware -- a collection of plugins which handle incoming
195
106
  // http(s) requests, routing them to static pages or JS functions.
196
- const devServer = createDevServerMiddleware({
197
- host: cliOptions.host,
198
- port: metroConfig.server.port,
199
- watchFolders: metroConfig.watchFolders,
200
- });
201
- const middleware = devServer.middleware;
202
- middleware.use(indexPageMiddleware);
203
-
204
- // merge the Metro config middleware with our middleware
205
- const enhanceMiddleware = metroConfig.server.enhanceMiddleware;
206
- // @ts-expect-error We want to assign to read-only `enhanceMiddleware`
207
- metroConfig.server.enhanceMiddleware = (
208
- metroMiddleware: Middleware,
209
- metroServer: Server
210
- ) => {
211
- return middleware.use(
212
- enhanceMiddleware
213
- ? enhanceMiddleware(metroMiddleware, metroServer)
214
- : metroMiddleware
215
- );
216
- };
107
+ const host = args.host?.length ? args.host : "localhost";
108
+ const devServer = createDevServerMiddleware({ host, port, watchFolders });
109
+
110
+ const coreDevMiddleware = (() => {
111
+ try {
112
+ // https://github.com/facebook/react-native/blob/3e7a873f2d1c5170a7f4c88064897e74a149c5d5/packages/community-cli-plugin/src/commands/start/runServer.js#L115
113
+ const { createDevMiddleware } = requireExternal(
114
+ "@react-native/dev-middleware"
115
+ );
116
+ return createDevMiddleware({
117
+ projectRoot,
118
+ logger,
119
+ unstable_experiments: {
120
+ // NOTE: Only affects the /open-debugger endpoint
121
+ enableCustomDebuggerFrontend: true,
122
+ },
123
+ });
124
+ } catch (_) {
125
+ // Fallback to the behavior from before 0.73
126
+ const middleware = devServer.middleware;
127
+ middleware.use(indexPageMiddleware);
128
+
129
+ // merge the Metro config middleware with our middleware
130
+ const enhanceMiddleware = metroConfig.server.enhanceMiddleware;
131
+ // @ts-expect-error We want to override `enhanceMiddleware`
132
+ metroConfig.server.enhanceMiddleware = (
133
+ metroMiddleware: Middleware,
134
+ metroServer: Server
135
+ ) => {
136
+ return middleware.use(
137
+ enhanceMiddleware
138
+ ? enhanceMiddleware(metroMiddleware, metroServer)
139
+ : metroMiddleware
140
+ );
141
+ };
142
+ return undefined;
143
+ }
144
+ })();
217
145
 
218
146
  // `createDevServerMiddleware` changed its return type in
219
147
  // https://github.com/react-native-community/cli/pull/1560
220
148
  let websocketEndpoints: RunServerOptions["websocketEndpoints"] = undefined;
221
149
  let messageSocketEndpoint: DevServerMiddleware["messageSocketEndpoint"];
150
+ let reportEventDelegate: Reporter["update"] | undefined = undefined;
222
151
 
223
152
  if (!hasAttachToServerFunction(devServer)) {
224
153
  websocketEndpoints = devServer.websocketEndpoints;
@@ -228,15 +157,42 @@ export async function rnxStart(
228
157
  reportEventDelegate = devServer.eventsSocketEndpoint.reportEvent;
229
158
  }
230
159
 
231
- // start the Metro server
232
- const serverOptions = {
233
- host: cliOptions.host,
234
- secure: cliOptions.https,
235
- secureCert: cliOptions.cert,
236
- secureKey: cliOptions.key,
237
- websocketEndpoints,
160
+ const printHelp = makeHelp(terminal, {
161
+ hasDebugger: Boolean(coreDevMiddleware),
162
+ });
163
+
164
+ // @ts-expect-error We want to override `reporter`
165
+ metroConfig.reporter = {
166
+ update(event: ReportableEvent) {
167
+ terminalReporter.update(event);
168
+ if (reportEventDelegate) {
169
+ reportEventDelegate(event);
170
+ }
171
+ if (interactive && event.type === "dep_graph_loading") {
172
+ printHelp();
173
+ }
174
+ },
238
175
  };
239
- const serverInstance = await startServer(metroConfig, serverOptions);
176
+
177
+ const serverInstance = await startServer(metroConfig, {
178
+ host: args.host,
179
+ secure: args.https,
180
+ secureCert: args.cert,
181
+ secureKey: args.key,
182
+ ...(coreDevMiddleware
183
+ ? {
184
+ unstable_extraMiddleware: [
185
+ devServer.middleware,
186
+ indexPageMiddleware,
187
+ coreDevMiddleware.middleware,
188
+ ],
189
+ websocketEndpoints: {
190
+ ...websocketEndpoints,
191
+ ...coreDevMiddleware.websocketEndpoints,
192
+ },
193
+ }
194
+ : { websocketEndpoints }),
195
+ });
240
196
 
241
197
  if (hasAttachToServerFunction(devServer)) {
242
198
  const { messageSocket, eventsSocket } =
@@ -245,6 +201,10 @@ export async function rnxStart(
245
201
 
246
202
  // bind our `reportEvent` delegate to the Metro server
247
203
  reportEventDelegate = eventsSocket.reportEvent;
204
+ } else {
205
+ // `messageSocketEndpoint` should already be set at this point. But this
206
+ // makes TypeScript happier.
207
+ messageSocketEndpoint = devServer.messageSocketEndpoint;
248
208
  }
249
209
 
250
210
  // In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In
@@ -262,55 +222,11 @@ export async function rnxStart(
262
222
  // in interactive mode, listen for keyboard events from stdin and bind
263
223
  // them to specific actions.
264
224
  if (interactive) {
265
- readline.emitKeypressEvents(process.stdin);
266
-
267
- process.stdin.setRawMode(true);
268
- process.stdin.on("keypress", (_key, data) => {
269
- const { ctrl, name } = data;
270
- if (ctrl === true) {
271
- switch (name) {
272
- case "c":
273
- terminal.log(chalk.green("Exiting..."));
274
- process.exit();
275
- break;
276
- case "z":
277
- process.emit("SIGTSTP", "SIGTSTP");
278
- break;
279
- }
280
- } else {
281
- switch (name) {
282
- case "a": {
283
- const protocol = cliOptions.https ? "https" : "http";
284
- const host = cliOptions.host || os.hostname();
285
- const port = metroConfig.server.port;
286
- const url = `${protocol}://${host}:${port}/index.bundle`;
287
- qrcode.toString(url, { type: "terminal" }, (_err, qr) => {
288
- terminal.log("");
289
- terminal.log(url + ":");
290
- terminal.log(qr);
291
- });
292
- break;
293
- }
294
-
295
- case "d":
296
- terminal.log(chalk.green("Opening developer menu..."));
297
- messageSocketEndpoint.broadcast("devMenu", undefined);
298
- break;
299
-
300
- case "h":
301
- printHelp();
302
- break;
303
-
304
- case "r":
305
- terminal.log(chalk.green("Reloading app..."));
306
- messageSocketEndpoint.broadcast("reload", undefined);
307
- break;
308
-
309
- case "return":
310
- terminal.log("");
311
- break;
312
- }
313
- }
225
+ attachKeyHandlers({
226
+ devServerUrl: `${scheme}://${host}:${port}`,
227
+ help: printHelp,
228
+ messageSocketEndpoint,
229
+ terminal,
314
230
  });
315
231
  }
316
232
  }
@@ -13,7 +13,7 @@ type CliThirdPartyNoticesOptions = {
13
13
  };
14
14
 
15
15
  export function rnxWriteThirdPartyNotices(
16
- _argv: Array<string>,
16
+ _argv: string[],
17
17
  _config: CLIConfig,
18
18
  {
19
19
  additionalText,