Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/funky-nails-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"stagewise": minor
---

Add HTTPS proxy support for development apps with self-signed certificates
10 changes: 10 additions & 0 deletions apps/cli/src/config/argparse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ program
myParsePath,
process.cwd(),
)
.option(
'--app-https',
'Use HTTPS when proxying the development app (for apps with self-signed certificates)',
)
.option('-s, --silent', 'Will not request user input or guide through setup')
.option('-v, --verbose', 'Output debug information to the CLI')
.option(
Expand Down Expand Up @@ -146,6 +150,7 @@ program.parse([...process.argv.slice(0, 2), ...stagewiseArgs]);
// Initialize variables
let port: number | undefined;
let appPort: number | undefined;
let appHttps: boolean;
let workspace: string;
let silent: boolean;
let verbose: boolean;
Expand All @@ -160,6 +165,7 @@ if (commandExecuted === 'auth' || commandExecuted === 'telemetry') {
// Set default values for auth and telemetry commands
port = undefined;
appPort = undefined;
appHttps = false;
workspace = process.cwd();
silent = false;
verbose = false;
Expand All @@ -169,6 +175,7 @@ if (commandExecuted === 'auth' || commandExecuted === 'telemetry') {
const {
port: parsedPort,
appPort: parsedAppPort,
appHttps: parsedAppHttps,
workspace: parsedWorkspace,
silent: parsedSilent,
verbose: parsedVerbose,
Expand All @@ -177,6 +184,7 @@ if (commandExecuted === 'auth' || commandExecuted === 'telemetry') {
} = options as {
port?: number;
appPort?: number;
appHttps?: boolean;
workspace: string;
silent: boolean;
verbose: boolean;
Expand All @@ -191,6 +199,7 @@ if (commandExecuted === 'auth' || commandExecuted === 'telemetry') {

port = parsedPort;
appPort = parsedAppPort;
appHttps = parsedAppHttps || false;
workspace = parsedWorkspace;
silent = parsedSilent;
verbose = parsedVerbose;
Expand All @@ -202,6 +211,7 @@ if (commandExecuted === 'auth' || commandExecuted === 'telemetry') {
export {
port,
appPort,
appHttps,
workspace,
silent,
verbose,
Expand Down
4 changes: 4 additions & 0 deletions apps/cli/src/config/config-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ const configFileSchema = z.object({
.max(65535)
.optional()
.describe('Port number for your development app'),
appHttps: z
.boolean()
.optional()
.describe('Whether the development app uses HTTPS'),
autoPlugins: z.boolean().optional(),
plugins: z.array(pluginSchema).optional(),
});
Expand Down
3 changes: 3 additions & 0 deletions apps/cli/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class ConfigResolver {
this.config = {
port: args.port || 3100,
appPort,
appHttps: args.appHttps || configFile?.appHttps || false,
dir: args.workspace,
silent: args.silent,
verbose: args.verbose,
Expand Down Expand Up @@ -120,6 +121,7 @@ export class ConfigResolver {
// Merge configurations (CLI args override config file)
const port = args.port || configFile?.port || 3100;
let appPort = args.appPort || configFile?.appPort;
const appHttps = args.appHttps || configFile?.appHttps || false;
const autoPlugins = configFile?.autoPlugins ?? true;
const plugins = configFile?.plugins ?? [];

Expand Down Expand Up @@ -232,6 +234,7 @@ export class ConfigResolver {
this.config = {
port,
appPort,
appHttps,
dir: args.workspace,
silent: args.silent,
verbose: args.verbose,
Expand Down
2 changes: 2 additions & 0 deletions apps/cli/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface CliArgs {
export interface ConfigFile {
port?: number;
appPort?: number;
appHttps?: boolean;
autoPlugins?: boolean;
plugins?: Array<string | { name: string; path?: string; url?: string }>;
eddyMode?: string;
Expand All @@ -19,6 +20,7 @@ export interface ConfigFile {
export interface Config {
port: number;
appPort: number;
appHttps: boolean;
dir: string;
silent: boolean;
verbose: boolean;
Expand Down
5 changes: 4 additions & 1 deletion apps/cli/src/server/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { applyHeaderRewrites } from './proxy-utils/headers-rewrites';

export const proxy = createProxyMiddleware({
changeOrigin: true,
secure: false, // Allow self-signed certificates
pathFilter: (pathname: string, req: IncomingMessage) => {
// Don't proxy if:
// - path starts with "stagewise-toolbar-app" (including agent server routes)
Expand All @@ -28,7 +29,9 @@ export const proxy = createProxyMiddleware({
followRedirects: false, // Don't automatically follow redirects to prevent loops
router: () => {
const config = configResolver.getConfig();
return `http://localhost:${config.appPort}`;
// Use HTTPS if configured, otherwise HTTP
const protocol = config.appHttps ? 'https' : 'http';
return `${protocol}://localhost:${config.appPort}`;
},
ws: false, // we handle websocket upgrades manually because we have multiple potential websocket servers
cookieDomainRewrite: {
Expand Down