MCPcopy Create free account
hub / github.com/heygen-com/hyperframes / findPortAndServe

Function findPortAndServe

packages/cli/src/server/portUtils.ts:340–418  ·  view source on GitHub ↗
(
  fetch: Parameters<typeof import("@hono/node-server").serve>[0]["fetch"],
  startPort: number,
  projectDir: string,
  forceNew: boolean,
  expectedServerBuildSignature: string | null = null,
  bindHost?: string,
)

Source from the content-addressed store, hash-verified

338 * 4. If bind still fails with EADDRINUSE (race) → retry next port
339 */
340export async function findPortAndServe(
341 fetch: Parameters<typeof import("@hono/node-server").serve>[0]["fetch"],
342 startPort: number,
343 projectDir: string,
344 forceNew: boolean,
345 expectedServerBuildSignature: string | null = null,
346 bindHost?: string,
347): Promise<FindPortResult> {
348 const { createAdaptorServer } = await import("@hono/node-server");
349 // SECURITY (F-001): bind to loopback by default. The studio API exposes
350 // unauthenticated project file read/write/delete + render-spawn endpoints;
351 // a bare `listen(port)` binds the unspecified address (`::`/`0.0.0.0`),
352 // handing those endpoints to anyone on the LAN. Operators who genuinely
353 // need LAN exposure opt in explicitly via the HYPERFRAMES_PREVIEW_HOST
354 // env var (e.g. HYPERFRAMES_PREVIEW_HOST=0.0.0.0).
355 const host = bindHost ?? (process.env.HYPERFRAMES_PREVIEW_HOST?.trim() || "127.0.0.1");
356 const normalizedDir = resolve(projectDir).replace(/\\/g, "/").toLowerCase();
357 const endPort = startPort + MAX_PORT_SCAN - 1;
358
359 let server: import("@hono/node-server").ServerType | null = null;
360
361 for (let port = startPort; port <= endPort; port++) {
362 const available = await testPortOnAllHosts(port);
363
364 if (available) {
365 // Lazily create server on first available port
366 if (!server) server = createAdaptorServer({ fetch });
367
368 try {
369 await new Promise<void>((resolveListener, rejectListener) => {
370 const onError = (err: NodeJS.ErrnoException): void => {
371 server!.removeListener("listening", onListening);
372 rejectListener(err);
373 };
374 const onListening = (): void => {
375 server!.removeListener("error", onError);
376 resolveListener();
377 };
378 server!.once("error", onError);
379 server!.once("listening", onListening);
380 server!.listen(port, host);
381 });
382 return { type: "started", server, port };
383 } catch (err: unknown) {
384 if ((err as NodeJS.ErrnoException).code === "EADDRINUSE") {
385 continue;
386 }
387 throw err;
388 }
389 }
390
391 // Port is occupied — probe for existing HyperFrames instance
392 if (!forceNew) {
393 const detection = await detectHyperframesServer(
394 port,
395 normalizedDir,
396 expectedServerBuildSignature,
397 );

Callers 2

runEmbeddedModeFunction · 0.85
portUtils.test.tsFile · 0.85

Calls 6

resolveFunction · 0.85
testPortOnAllHostsFunction · 0.85
detectHyperframesServerFunction · 0.85
getProcessOnPortFunction · 0.85
onceMethod · 0.80
listenMethod · 0.80

Tested by

no test coverage detected