Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ export function buildHealth(connected: boolean): BridgeHealth {
startedAt: STARTED_AT,
bootMinute: BOOT_MINUTE,
browser: { connected },
headed: shouldRunHeaded(),
};
}

Expand Down
6 changes: 4 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { request } from "node:http";
import { AxiError } from "axi-sdk-js";
import {
resolveBridgeLauncher,
shouldRunHeaded,
type LastSnapshotCache,
} from "./bridge.js";
import {
Expand Down Expand Up @@ -378,19 +379,20 @@ async function probeAll(ports: number[]): Promise<PortProbe[]> {
*/
export async function findUsableBridge(ports: number[]): Promise<number | null> {
const version = getPackageVersion();
const wantHeaded = shouldRunHeaded();

// Fast path: the port in the PID file is nearly always the answer, and
// checking it alone keeps the common case to a single round trip.
const preferred = readPidFile()?.port;
if (preferred !== undefined && ports.includes(preferred)) {
const health = await probeHealth(preferred);
if (isUsableBridge(health, version)) return preferred;
if (isUsableBridge(health, version) && health.headed === wantHeaded) return preferred;
if (isOurBridge(health)) await shutdownBridgeOnPort(preferred, health);
}

const probes = await probeAll(ports.filter((p) => p !== preferred));
for (const { port, health } of probes) {
if (isUsableBridge(health, version)) return port;
if (isUsableBridge(health, version) && health.headed === wantHeaded) return port;
}
for (const { port, health } of probes) {
if (isOurBridge(health)) await shutdownBridgeOnPort(port, health);
Expand Down
4 changes: 4 additions & 0 deletions src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export interface BridgeHealth {
startedAt: number;
bootMinute: number;
browser: { connected: boolean };
/** Whether the bridge launched the browser in headed (visible) mode. */
headed: boolean;
}

/**
Expand Down Expand Up @@ -107,5 +109,7 @@ export function parseHealth(body: string): BridgeHealth | null {
bootMinute:
typeof record.bootMinute === "number" ? record.bootMinute : Number.NaN,
browser: { connected: browser?.connected === true },
// Pre-0.2.7 bridges omit headed; they launched headless by default.
headed: typeof record.headed === "boolean" ? record.headed : false,
};
}
2 changes: 2 additions & 0 deletions test/bridge-lifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { join } from "node:path";
import { spawn, type ChildProcess } from "node:child_process";
import { BRIDGE_SERVER_NAME, computeBootMinute } from "../src/identity.js";
import { getPackageVersion } from "../src/version.js";
import { shouldRunHeaded } from "../src/bridge.js";

type ClientModule = typeof import("../src/client.js");

Expand Down Expand Up @@ -47,6 +48,7 @@ function bridgeHealth(overrides: Record<string, unknown> = {}): Record<string, u
startedAt: Date.now(),
bootMinute: computeBootMinute(),
browser: { connected: true },
headed: shouldRunHeaded(),
...overrides,
};
}
Expand Down
1 change: 1 addition & 0 deletions test/identity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function health(overrides: Partial<BridgeHealth> = {}): BridgeHealth {
startedAt: 1_700_000_000_000,
bootMinute: 28_000_000,
browser: { connected: true },
headed: true,
...overrides,
};
}
Expand Down
Loading