diff --git a/packages/apps/src/http/express-adapter.spec.ts b/packages/apps/src/http/express-adapter.spec.ts index 4de746b42..b1286a8e5 100644 --- a/packages/apps/src/http/express-adapter.spec.ts +++ b/packages/apps/src/http/express-adapter.spec.ts @@ -1,5 +1,6 @@ import fs from 'fs'; import http from 'http'; +import https from 'https'; import os from 'os'; import path from 'path'; @@ -10,7 +11,7 @@ import supertest from 'supertest'; import { ExpressAdapter } from './express-adapter'; describe('ExpressAdapter', () => { - let server: http.Server; + let server: http.Server | https.Server; let adapter: ExpressAdapter; afterEach(() => { @@ -196,4 +197,36 @@ describe('ExpressAdapter', () => { } }); }); + + describe('HTTPS server support', () => { + it('should accept an https.Server and wire it up correctly', async () => { + // https.createServer() without certs creates a valid server object + // that is instanceof https.Server (but NOT instanceof http.Server) + const httpsServer = https.createServer({}); + + expect(httpsServer instanceof https.Server).toBe(true); + expect(httpsServer instanceof http.Server).toBe(false); + + expect(() => { + adapter = new ExpressAdapter(httpsServer); + }).not.toThrow(); + + // Verify the adapter stored the server: stop() should reject with + // "Server is not running" (not "managed externally" which would mean + // the adapter didn't recognize the https.Server and created its own) + await expect(adapter.stop()).rejects.toThrow('Server is not running'); + }); + + it('should register routes on https.Server', () => { + const httpsServer = https.createServer({}); + adapter = new ExpressAdapter(httpsServer); + + // Should not throw — routes register on the internal Express app + expect(() => { + adapter.registerRoute('POST', '/api/messages', async () => { + return { status: 200, body: { ok: true } }; + }); + }).not.toThrow(); + }); + }); }); diff --git a/packages/apps/src/http/express-adapter.ts b/packages/apps/src/http/express-adapter.ts index 60e39c2fb..887ec9b70 100644 --- a/packages/apps/src/http/express-adapter.ts +++ b/packages/apps/src/http/express-adapter.ts @@ -1,4 +1,5 @@ import http from 'http'; +import https from 'https'; import cors from 'cors'; import express from 'express'; @@ -27,12 +28,12 @@ export class ExpressAdapter implements IHttpServerAdapter { readonly use: express.Application['use']; protected express: express.Application; - protected server?: http.Server; + protected server?: http.Server | https.Server; protected logger: ILogger; protected onError?: (err: Error) => void; - constructor(serverOrApp?: http.Server | express.Application, options?: { logger?: ILogger; onError?: (err: Error) => void }) { - if (serverOrApp instanceof http.Server) { + constructor(serverOrApp?: http.Server | https.Server | express.Application, options?: { logger?: ILogger; onError?: (err: Error) => void }) { + if (serverOrApp instanceof http.Server || serverOrApp instanceof https.Server) { // The adapter handles all requests on this server. Use the adapter's // methods (get, post, use, etc.) to add routes. If you need your own // Express app, pass it in instead and manage the server yourself. diff --git a/packages/dev/src/plugin.ts b/packages/dev/src/plugin.ts index de84379d2..f215de91a 100644 --- a/packages/dev/src/plugin.ts +++ b/packages/dev/src/plugin.ts @@ -103,8 +103,20 @@ export class DevtoolsPlugin { } onStart({ port }: IPluginStartEvent) { - const numericPort = this.options.customPort ?? ( - typeof port === 'string' ? parseInt(port, 10) + 1 : port + 1); + let numericPort: number; + if (this.options.customPort) { + numericPort = this.options.customPort; + } else if (typeof port === 'number') { + numericPort = port + 1; + } else { + const parsed = parseInt(port, 10); + if (isNaN(parsed)) { + numericPort = 3979; + this.log.warn(`Port is a named pipe (${port}), using default devtools port ${numericPort}. Set customPort to override.`); + } else { + numericPort = parsed + 1; + } + } this.express.use( router({