mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-21 21:31:12 +02:00
fix(apps): bind IPv6 loopback too — blank apps in-app
macOS's resolver maps *.apps.localhost to ::1 only, so Electron's iframe connects to [::1]:3210 while the server listened on 127.0.0.1 only — connection refused, blank app, while external browsers succeeded via their own IPv4 fallback. Listen on both loopback addresses (::1 best-effort for IPv6-disabled machines).
This commit is contained in:
parent
7f15f67273
commit
c81739f9f7
1 changed files with 27 additions and 1 deletions
|
|
@ -54,6 +54,11 @@ const MIME_TYPES: Record<string, string> = {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
let server: Server | null = null;
|
let server: Server | null = null;
|
||||||
|
// IPv6 loopback listener. REQUIRED on macOS: the OS resolver maps
|
||||||
|
// *.apps.localhost to ::1 (only), so Electron's iframe connects to [::1]:3210 —
|
||||||
|
// binding just 127.0.0.1 makes in-app requests fail (blank app) while external
|
||||||
|
// browsers succeed via their own IPv4 fallback.
|
||||||
|
let server6: Server | null = null;
|
||||||
let startPromise: Promise<void> | null = null;
|
let startPromise: Promise<void> | null = null;
|
||||||
let watcher: FSWatcher | null = null;
|
let watcher: FSWatcher | null = null;
|
||||||
let serverError: string | null = null;
|
let serverError: string | null = null;
|
||||||
|
|
@ -708,8 +713,9 @@ export async function init(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await fsp.mkdir(APPS_DIR, { recursive: true });
|
await fsp.mkdir(APPS_DIR, { recursive: true });
|
||||||
await startWatcher();
|
await startWatcher();
|
||||||
|
const expressApp = createApp();
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
const s = createApp().listen(APPS_PORT, '127.0.0.1', () => {
|
const s = expressApp.listen(APPS_PORT, '127.0.0.1', () => {
|
||||||
server = s;
|
server = s;
|
||||||
serverError = null;
|
serverError = null;
|
||||||
console.log(`[Apps] server on 127.0.0.1:${APPS_PORT} (host suffix ${APPS_HOST_SUFFIX}), dir ${APPS_DIR}`);
|
console.log(`[Apps] server on 127.0.0.1:${APPS_PORT} (host suffix ${APPS_HOST_SUFFIX}), dir ${APPS_DIR}`);
|
||||||
|
|
@ -724,6 +730,18 @@ export async function init(): Promise<void> {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// Dual-stack loopback: also listen on ::1 (see server6 note above).
|
||||||
|
// Best-effort — some machines have IPv6 disabled.
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const s6 = expressApp.listen(APPS_PORT, '::1', () => {
|
||||||
|
server6 = s6;
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
s6.on('error', (error: NodeJS.ErrnoException) => {
|
||||||
|
console.warn(`[Apps] IPv6 loopback listen failed (${error.code}); continuing IPv4-only`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
serverError = error instanceof Error ? error.message : String(error);
|
serverError = error instanceof Error ? error.message : String(error);
|
||||||
await shutdown();
|
await shutdown();
|
||||||
|
|
@ -753,6 +771,14 @@ export async function shutdown(): Promise<void> {
|
||||||
}
|
}
|
||||||
eventClients.clear();
|
eventClients.clear();
|
||||||
|
|
||||||
|
const s6 = server6;
|
||||||
|
server6 = null;
|
||||||
|
if (s6) {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
s6.close(() => resolve());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const s = server;
|
const s = server;
|
||||||
server = null;
|
server = null;
|
||||||
if (!s) return;
|
if (!s) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue