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

Function startServer

apps/host-selfhost/src/serve.ts:95–138  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

93 );
94
95export const startServer = async (): Promise<void> => {
96 const config = loadConfig();
97 const { AppLayer, betterAuth } = await makeSelfHostApp();
98
99 // Serve the built SPA, split by cacheability so a redeploy is picked up at
100 // once instead of stranding browsers on a stale shell:
101 // - `/assets/*` are Vite content-hashed (a new build emits new filenames),
102 // so they're safe to cache forever.
103 // - index.html (and the SPA fallback for client routes) is the mutable
104 // entry point that references those hashes; it must always revalidate, or
105 // a browser keeps an old index.html plus its old hashed bundles (still in
106 // cache) and renders a stale UI until a hard refresh.
107 // Without explicit headers `HttpStaticServer` sends no Cache-Control at all,
108 // so browsers heuristically cache index.html across deploys. The hashed
109 // `/assets` route is the more specific match, so it wins over the SPA
110 // catch-all. Other built-in API/docs/auth/mcp routes still take precedence;
111 // `spa: true` falls back to index.html for any remaining path (client routing).
112 const AssetsLive = HttpStaticServer.layer({
113 root: assetsDir,
114 prefix: "/assets",
115 cacheControl: "public, max-age=31536000, immutable",
116 }).pipe(Layer.provide(BunFileSystem.layer), Layer.provide(BunPath.layer));
117
118 const SpaLive = HttpStaticServer.layer({
119 root: distDir,
120 spa: true,
121 cacheControl: "no-cache",
122 }).pipe(Layer.provide(BunFileSystem.layer), Layer.provide(BunPath.layer));
123
124 // Server-scope finalizer: flush buffered analytics on graceful shutdown.
125 const AnalyticsFlushLive = Layer.effectDiscard(
126 Effect.addFinalizer(() => Effect.promise(() => disposeAnalytics())),
127 );
128
129 const ServerLive = HttpRouter.serve(Layer.mergeAll(AppLayer, AssetsLive, SpaLive), {
130 middleware: selfHostHttpMiddleware(betterAuth),
131 }).pipe(
132 Layer.provide(
133 BunHttpServer.layer({ hostname: config.host, port: config.port, idleTimeout: 0 }),
134 ),
135 );
136
137 await BunRuntime.runMain(Layer.launch(Layer.merge(ServerLive, AnalyticsFlushLive)));
138};
139
140if (import.meta.main) {
141 // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: process entry point; turn a pre-runtime startup failure (config/DB open) into a diagnosable log + non-zero exit instead of an opaque unhandled rejection

Callers 1

serve.tsFile · 0.70

Calls 4

loadConfigFunction · 0.90
makeSelfHostAppFunction · 0.90
disposeAnalyticsFunction · 0.90
selfHostHttpMiddlewareFunction · 0.85

Tested by

no test coverage detected