Skip to content

Commit 69ca83b

Browse files
authored
fix(cli): add robust browser support for --open flag (#242)
Approved by Nik. Merging
1 parent 4e2fb0e commit 69ca83b

File tree

1 file changed

+48
-13
lines changed

1 file changed

+48
-13
lines changed

apps/typesync/src/subcommands/studio.ts

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as Console from 'effect/Console';
77
import * as Data from 'effect/Data';
88
import * as Effect from 'effect/Effect';
99
import * as Layer from 'effect/Layer';
10-
import open, { type AppName } from 'open';
10+
import open, { type AppName, apps } from 'open';
1111

1212
import * as Server from '../Server.js';
1313

@@ -22,7 +22,15 @@ export const typesync = Command.make('typesync', {
2222
Options.withDescription('If true, opens the Typesync studio in your browser'),
2323
Options.withDefault(true),
2424
),
25-
browser: Options.choice('browser', ['chrome', 'firefox', 'edge', 'browser', 'browserPrivate']).pipe(
25+
browser: Options.choice('browser', [
26+
'chrome',
27+
'firefox',
28+
'edge',
29+
'safari',
30+
'arc',
31+
'browser',
32+
'browserPrivate',
33+
]).pipe(
2634
Options.withAlias('b'),
2735
Options.withDescription('Broweser to open the Typesync studio app in. Default is your default selected browser'),
2836
Options.withDefault('browser'),
@@ -60,19 +68,46 @@ export const typesync = Command.make('typesync', {
6068
),
6169
);
6270

63-
const openBrowser = (port: number, browser: AppName) =>
71+
const openBrowser = (port: number, browser: AppName | 'arc' | 'safari' | 'browser' | 'browserPrivate') =>
6472
Effect.async<void, OpenBrowserError>((resume) => {
65-
open(`http://localhost:${port}`, {
66-
app: { name: browser },
67-
}).then((subprocess) => {
68-
// wait for child process to start before succeeding
69-
subprocess.on('spawn', () => {
70-
resume(Effect.void);
71-
});
72-
subprocess.on('error', (err) => {
73-
resume(Effect.fail(new OpenBrowserError({ cause: err })));
73+
const url = `http://localhost:${port}`;
74+
75+
const launch = (appOpts?: { name: string | readonly string[] }) =>
76+
open(url, appOpts ? { app: appOpts } : undefined).then((subprocess) => {
77+
subprocess.on('spawn', () => resume(Effect.void));
78+
subprocess.on('error', (err) => resume(Effect.fail(new OpenBrowserError({ cause: err }))));
7479
});
75-
});
80+
81+
const mapBrowserName = (b: typeof browser): string | readonly string[] | undefined => {
82+
switch (b) {
83+
case 'chrome':
84+
return apps.chrome; // cross-platform alias from open
85+
case 'firefox':
86+
return apps.firefox;
87+
case 'edge':
88+
return apps.edge;
89+
case 'safari':
90+
return 'Safari';
91+
case 'arc':
92+
return 'Arc';
93+
default:
94+
return undefined;
95+
}
96+
};
97+
98+
switch (browser) {
99+
case 'browser':
100+
launch();
101+
break;
102+
case 'browserPrivate':
103+
launch({ name: apps.browserPrivate });
104+
break;
105+
default: {
106+
const mapped = mapBrowserName(browser);
107+
mapped ? launch({ name: mapped }).catch(() => launch()) : launch();
108+
break;
109+
}
110+
}
76111
});
77112

78113
export class OpenBrowserError extends Data.TaggedError('/typesync/errors/OpenBrowserError')<{

0 commit comments

Comments
 (0)