MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / startServer

Function startServer

apps/local/src/serve.ts:332–539  ·  view source on GitHub ↗
(opts: StartServerOptions = {})

Source from the content-addressed store, hash-verified

330};
331
332export async function startServer(opts: StartServerOptions = {}): Promise<ServerInstance> {
333 const port = opts.port ?? parseInt(process.env.PORT ?? "4788", 10);
334 const hostname = opts.hostname ?? "127.0.0.1";
335 // ONE credential, always present: an explicit override or the stable token
336 // from auth.json (minted on first run). Auth is unconditionally on — loopback
337 // is no longer a free pass, since Executor runs arbitrary code that any local
338 // process could otherwise drive.
339 const authToken = normalizeCredential(opts.authToken) ?? loadOrMintLocalAuthToken();
340 const isAuthorized = makeIsAuthorized(authToken);
341 // CORS-only origin allowlist (no Host gate — the bearer is the boundary).
342 const corsAllowedHosts = new Set<string>([
343 ...DEFAULT_ALLOWED_HOSTS,
344 ...(opts.allowedHosts ?? []),
345 ]);
346 const clientDir = opts.clientDir ?? resolve(import.meta.dirname, "../dist");
347
348 startIntegrationsRefresh();
349
350 const ownsHandlers = opts.handlers === undefined;
351 const handlers = opts.handlers ?? (await getServerHandlers(authToken));
352 let viteChild: ViteChild | null = null;
353
354 const disposeOwnedResources = async (): Promise<void> => {
355 setOAuthCompletionListener(null);
356 if (ownsHandlers) {
357 await disposeServerHandlers();
358 } else {
359 await closeProvidedHandlers(handlers);
360 }
361 // Final analytics flush; the layer finalizer drains the buffer.
362 await disposeAnalytics();
363 if (viteChild) await viteChild.stop();
364 };
365
366 // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: after handlers boot, failed static/dev/Bun startup must release DB ownership before surfacing the startup error
367 try {
368 // Mirror every OAuth callback completion into the local in-memory result
369 // store. The Electron desktop renderer polls /api/oauth/await/:sessionId
370 // for these when the user runs the flow in their system browser (no
371 // shared origin → no postMessage). Cloud doesn't register a listener;
372 // its same-origin web SPA receives results via postMessage directly.
373 setOAuthCompletionListener((result) => publishOAuthResult(result));
374
375 // Build static routes from either embedded assets, disk, or a spawned
376 // vite dev child (EXECUTOR_DEV=1). Vite mode takes precedence and
377 // disables the file-extension 404 short-circuit since vite serves
378 // hashed asset paths directly.
379 let staticRoutes: Record<string, StaticHandler> = {};
380 let serveIndex: StaticHandler;
381
382 const devMode = process.env.EXECUTOR_DEV === "1" && !opts.embeddedWebUI;
383 if (devMode) {
384 console.log("[executor] EXECUTOR_DEV=1 — spawning vite dev child for live UI");
385 viteChild = await startViteChild();
386 // Diagnostic only — this is the internal vite port the daemon proxies to.
387 // It must NOT read as a destination: the URL to open is the `Open:` line the
388 // CLI prints (the daemon port, with ?_token). Hitting the vite port directly
389 // skips that bootstrap and lands on the auth gate.

Callers 5

server.tsFile · 0.90
startTestServerFunction · 0.90
serve.test.tsFile · 0.90
serve.tsFile · 0.70

Calls 14

normalizeCredentialFunction · 0.90
loadOrMintLocalAuthTokenFunction · 0.90
makeIsAuthorizedFunction · 0.90
startIntegrationsRefreshFunction · 0.90
getServerHandlersFunction · 0.90
publishOAuthResultFunction · 0.90
startViteChildFunction · 0.85
embeddedToStaticRoutesFunction · 0.85
htmlResponseFunction · 0.85
collectStaticRoutesFunction · 0.85
ignoreCleanupFailureFunction · 0.85

Tested by 1

startTestServerFunction · 0.72