one default port, and it is 9000
Every PORT fallback in the tree now says 9000. There were three answers to one question, each defensible where it was written and none of them visible from the others: server.tsx and 19 sidecars 5000 a default from before there was an installer user-instance.ts 9010 what scripts/setup-old/setup.sh really wrote .env.example 9000 what we told people to write 5000 goes first because macOS binds it — AirPlay Receiver has owned it since Monterey, so a dev server there fails to bind or gets shadowed by something that answers. All 22 sites moved together, which is the point. Changing the app alone would have turned a consistent-but-wrong default into a split one: the app on 9000 while nineteen sidecars still dialled 5000. 9010 was the interesting one. It was the only value that ever matched a real machine, because it is what the old installer wrote — and it was in the single file whose disagreement would have broken chat alone, with nothing else looking wrong. Its own comment records the same bug being fixed once already, within the file, by a change that left it disagreeing with everything outside it. Note what these defaults actually are: the sidecars bind nothing. user-instance.ts has no listener at all — it builds ws:// and http:// URLs that both address the app's single listener. So every one of these numbers is a guess at where the app is, for a value that .env always supplies. Worth removing rather than aligning, which is a separate change. Not typechecked (empty node_modules, frozen installs). Every edited file parses under `bun build --no-bundle`; the pm2 profile loads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,7 @@ function defineProfile({ file, include, excluded }) {
|
|||||||
|
|
||||||
// `cwd` is pinned because Bun auto-loads .env from the working directory (and the pty sidecar does
|
// `cwd` is pinned because Bun auto-loads .env from the working directory (and the pty sidecar does
|
||||||
// `import 'dotenv/config'`). Without it, starting pm2 from anywhere but the repo root silently falls
|
// `import 'dotenv/config'`). Without it, starting pm2 from anywhere but the repo root silently falls
|
||||||
// back to PORT=5000 with no POSTGRES_URL.
|
// back to the default PORT with no POSTGRES_URL.
|
||||||
//
|
//
|
||||||
// It also decides where the install is. src/servers/data-path.ts derives OFFICER_ROOT as the PARENT of
|
// It also decides where the install is. src/servers/data-path.ts derives OFFICER_ROOT as the PARENT of
|
||||||
// the working directory, and data/, capabilities/ and dockers/ hang off that — so a wrong cwd does not
|
// the working directory, and data/, capabilities/ and dockers/ hang off that — so a wrong cwd does not
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ import './servers/api/chat/opencode/sidecar-server'; // subscribe to the opencod
|
|||||||
import type { SidecarRegistration } from './servers/sidecar/registration-protocol';
|
import type { SidecarRegistration } from './servers/sidecar/registration-protocol';
|
||||||
import { toShellUsername } from './servers/data-path';
|
import { toShellUsername } from './servers/data-path';
|
||||||
|
|
||||||
const { PORT = '5000' } = process.env;
|
const { PORT = '9000' } = process.env;
|
||||||
|
|
||||||
// Build static file routes from public/
|
// Build static file routes from public/
|
||||||
const publicRoutes: Record<string, (req: Request) => Response> = {};
|
const publicRoutes: Record<string, (req: Request) => Response> = {};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { logger } from './logger';
|
|||||||
/** A name has to survive being typed into a prompt and into a shell, so keep it boring. */
|
/** A name has to survive being typed into a prompt and into a shell, so keep it boring. */
|
||||||
const NAME_RE = /^[a-z0-9][a-z0-9-]{0,30}[a-z0-9]$|^[a-z0-9]$/;
|
const NAME_RE = /^[a-z0-9][a-z0-9-]{0,30}[a-z0-9]$|^[a-z0-9]$/;
|
||||||
|
|
||||||
const API_ORIGIN = `http://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_ORIGIN = `http://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
export function registerAgentPanelRoutes(router: Hono<any>): void {
|
export function registerAgentPanelRoutes(router: Hono<any>): void {
|
||||||
// GET /chat/agent-panels?dashboardId=… — the address book for one dashboard.
|
// GET /chat/agent-panels?dashboardId=… — the address book for one dashboard.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { sign } from '@@/jwt';
|
import { sign } from '@@/jwt';
|
||||||
|
|
||||||
const { PORT = '5000', PUBLIC_URL } = process.env;
|
const { PORT = '9000', PUBLIC_URL } = process.env;
|
||||||
|
|
||||||
const PUBLIC_HOST = (() => {
|
const PUBLIC_HOST = (() => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { DATA_PATH } from '../../data-path';
|
|||||||
// machine-facing interface. Same split officer-email already uses.
|
// machine-facing interface. Same split officer-email already uses.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { loadState, flushAndSave, acquireLock, releaseLock, getState } from './s
|
|||||||
import { startAnthropicProxy, getProxySecret, ensureProxySecret } from './proxy';
|
import { startAnthropicProxy, getProxySecret, ensureProxySecret } from './proxy';
|
||||||
import { createSidecarConnector } from '../connect';
|
import { createSidecarConnector } from '../connect';
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// ── Startup ──
|
// ── Startup ──
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,16 @@ async function resolveOwner() {
|
|||||||
const dbUser = await resolveOwner();
|
const dbUser = await resolveOwner();
|
||||||
const email = dbUser.email;
|
const email = dbUser.email;
|
||||||
|
|
||||||
// Same officer instance for both, so the fallback port has to agree. It used to default to 5000 for the
|
// Both URLs address the SAME officer instance — this file binds nothing, and the app serves HTTP and
|
||||||
// WebSocket and 9010 for the REST base, which would have split them apart if PORT were ever unset.
|
// WebSocket on one listener. So the fallback port has to agree, and twice it did not: 5000 for the
|
||||||
const OFFICER_PORT = process.env.PORT ?? '9010';
|
// WebSocket against 9010 for the REST base here, and then 9010 here against 5000 in the app and every
|
||||||
|
// other sidecar. The second one was the worse half, because chat is the only thing that would have
|
||||||
|
// broken and nothing else would have looked wrong.
|
||||||
|
//
|
||||||
|
// 9000 everywhere now, matching server.tsx and .env.example. 9010 was the old installer's default
|
||||||
|
// (scripts/setup-old/setup.sh), which is why it was the only one of the three that ever matched a real
|
||||||
|
// machine.
|
||||||
|
const OFFICER_PORT = process.env.PORT ?? '9000';
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${OFFICER_PORT}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${OFFICER_PORT}`;
|
||||||
const OFFICER_API_URL = process.env.OFFICER_API_URL ?? `http://127.0.0.1:${OFFICER_PORT}`;
|
const OFFICER_API_URL = process.env.OFFICER_API_URL ?? `http://127.0.0.1:${OFFICER_PORT}`;
|
||||||
const MCP_SERVER_SCRIPT = resolve(import.meta.dir, '../../mcp-tool-server.ts');
|
const MCP_SERVER_SCRIPT = resolve(import.meta.dir, '../../mcp-tool-server.ts');
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ type AnyCommand = SidecarCommand;
|
|||||||
type AnyEvent = SidecarEvent;
|
type AnyEvent = SidecarEvent;
|
||||||
|
|
||||||
type SidecarConnectorConfig = {
|
type SidecarConnectorConfig = {
|
||||||
apiUrl: string; // ws://127.0.0.1:5000/api/sidecar/register
|
apiUrl: string; // ws://127.0.0.1:9000/api/sidecar/register
|
||||||
name: string;
|
name: string;
|
||||||
capabilities: string[];
|
capabilities: string[];
|
||||||
onCommand: (cmd: AnyCommand, reply: (msg: AnyEvent) => void) => void;
|
onCommand: (cmd: AnyCommand, reply: (msg: AnyEvent) => void) => void;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { broadcastEmailNew } from './routes';
|
|||||||
import { startEmailServer } from './http';
|
import { startEmailServer } from './http';
|
||||||
import { createSidecarConnector } from '../connect';
|
import { createSidecarConnector } from '../connect';
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// The sidecar used to reach BACK into the platform's queue over this socket to get a sync run —
|
// The sidecar used to reach BACK into the platform's queue over this socket to get a sync run —
|
||||||
// enqueueViaWs / listJobsViaWs and a pending-response map. Syncs run in this process now
|
// enqueueViaWs / listJobsViaWs and a pending-response map. Syncs run in this process now
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import {
|
|||||||
// sidecar from being a general-purpose SSRF hop into whatever else is on that host.
|
// sidecar from being a general-purpose SSRF hop into whatever else is on that host.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// Everything under /api/v1 the UI legitimately needs.
|
// Everything under /api/v1 the UI legitimately needs.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ import { MIN_VERSION_LABEL } from './version';
|
|||||||
// — the mistake the Soulseek panels made with 37 raw upstream calls. Every quirk is absorbed here.
|
// — the mistake the Soulseek panels made with 37 raw upstream calls. Every quirk is absorbed here.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import { getConfig } from './upstream';
|
|||||||
// update/*, installation/*, mail config, settings writes, ownership transfer — is deliberately unreachable.
|
// update/*, installation/*, mail config, settings writes, ownership transfer — is deliberately unreachable.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ import { getConfig, probe } from './upstream';
|
|||||||
// general proxy, and why HLS forces it to keep Jellyfin's own paths.
|
// general proxy, and why HLS forces it to keep Jellyfin's own paths.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { callMemos, getMemosConfig, invalidateMemosConfig, normalizeBase, probe
|
|||||||
// SSRF hop into whatever else is on that host.
|
// SSRF hop into whatever else is on that host.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// Everything under /api/v1 the UI legitimately needs. Auth routes are excluded on purpose: signin and
|
// Everything under /api/v1 the UI legitimately needs. Auth routes are excluded on purpose: signin and
|
||||||
// signout would mint or destroy sessions on the instance, and this sidecar authenticates with a stored
|
// signout would mint or destroy sessions on the instance, and this sidecar authenticates with a stored
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ const asKeys = (v: unknown): string[] | null =>
|
|||||||
// `v` = per-album version stamp; unchanged `v` ⇒ nothing changed ⇒ the phone can skip re-downloading.
|
// `v` = per-album version stamp; unchanged `v` ⇒ nothing changed ⇒ the phone can skip re-downloading.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// ── Audio-streaming HTTP server ──
|
// ── Audio-streaming HTTP server ──
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import type { Notification, NotifyType } from './types';
|
|||||||
// the visible string is composed here rather than sent by the producer.
|
// the visible string is composed here rather than sent by the producer.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
const VALID_TYPES: NotifyType[] = ['job', 'mail', 'agent', 'download', 'test'];
|
const VALID_TYPES: NotifyType[] = ['job', 'mail', 'agent', 'download', 'test'];
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { runOpenCodeTurnOnServe, killServeTurn, listRunningServeTurns, stopAllSe
|
|||||||
// CRUD only, with turns spawned as `opencode run --dir <cwd>` subprocesses — that path was deleted on
|
// CRUD only, with turns spawned as `opencode run --dir <cwd>` subprocesses — that path was deleted on
|
||||||
// 2026-08-10 once the serve had streaming, mid-turn injection and interrupt working end to end.
|
// 2026-08-10 once the serve had streaming, mid-turn injection and interrupt working end to end.
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
const OPENCODE_BIN = process.env.OPENCODE_BIN || join(homedir(), '.opencode', 'bin', 'opencode');
|
const OPENCODE_BIN = process.env.OPENCODE_BIN || join(homedir(), '.opencode', 'bin', 'opencode');
|
||||||
const SERVE_CWD = join(DATA_PATH, 'opencode_server');
|
const SERVE_CWD = join(DATA_PATH, 'opencode_server');
|
||||||
const HEALTH_TIMEOUT_MS = 20_000;
|
const HEALTH_TIMEOUT_MS = 20_000;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import { getConfig } from './upstream';
|
|||||||
// ETag included. The administrative half of Immich's API is unreachable — see routes.ts for the list.
|
// ETag included. The administrative half of Immich's API is unreachable — see routes.ts for the list.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { startServer } from './server.mjs';
|
|||||||
|
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
const REGISTER_URL = `${API_URL}/api/sidecar/register`;
|
const REGISTER_URL = `${API_URL}/api/sidecar/register`;
|
||||||
const RECONNECT_DELAYS = [200, 500, 1000, 2000, 4000, 8000, 15000];
|
const RECONNECT_DELAYS = [200, 500, 1000, 2000, 4000, 8000, 15000];
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import { handleOfficerRoute } from './officer';
|
|||||||
// (src/servers/sidecar/vault/index.ts) once the client needs real-time updates. SignalR carries its
|
// (src/servers/sidecar/vault/index.ts) once the client needs real-time updates. SignalR carries its
|
||||||
// credential as an `?access_token=` query param on the socket, so the key injection differs from HTTP.
|
// credential as an `?access_token=` query param on the socket, so the key injection differs from HTTP.
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import { getTransmissionConfig } from './upstream';
|
|||||||
// platform, and which daemon to talk to is per-owner data.
|
// platform, and which daemon to talk to is per-owner data.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { getVaultBase, getVaultWsBase, stripHopByHop, redactPath } from './upstr
|
|||||||
// The server listens on a random loopback port, reported to the API on connect so it can route here.
|
// The server listens on a random loopback port, reported to the API on connect so it can route here.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as vncManager from './vnc-manager';
|
|||||||
import { createSidecarConnector } from '../connect';
|
import { createSidecarConnector } from '../connect';
|
||||||
import { getOwnerHomeDir } from '@@/data-path';
|
import { getOwnerHomeDir } from '@@/data-path';
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
// ── Command handlers ──
|
// ── Command handlers ──
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ import { invalidateAll } from './resolve';
|
|||||||
// WALLET_LOCKED from signing paths only; every read above keeps working.
|
// WALLET_LOCKED from signing paths only; every read above keeps working.
|
||||||
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
|
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '9000'}`;
|
||||||
|
|
||||||
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
/** Grab an ephemeral free port by briefly binding one and releasing it. */
|
||||||
function getFreePort(): number {
|
function getFreePort(): number {
|
||||||
|
|||||||
Reference in New Issue
Block a user