import { FileSystem, HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse, Path } from "@effect/platform" import { RpcServer } from "@effect/rpc" import { CommonConfig } from "@website/common/config" import { WebRpc, WebRpcSerializationDevelopment, WebRpcSerializationProduction } from "@website/common/webrpc" import { Duration, Effect, flow, Layer } from "effect" import { WebRpcLive } from "./webrpc" const router = HttpRouter.empty const makeWebRpcRoute = Effect.all([ CommonConfig.webRpcHttpPath, RpcServer.toHttpApp(WebRpc), ]).pipe( Effect.map(([path, app]) => HttpRouter.mountApp(path, app)), Effect.provide(WebRpcLive), ) const makeProductionWebappMiddleware = Effect.gen(function*() { const path = yield* Path.Path const fs = yield* FileSystem.FileSystem const dist = path.join(yield* path.fromFileUrl(new URL(".", import.meta.resolve("@website/webapp"))), "dist") return () => Effect.gen(function*() { const req = yield* HttpServerRequest.HttpServerRequest const source = path.join(dist, req.url) const isValid = yield* fs.stat(source).pipe( Effect.andThen(stat => stat.type === "File"), Effect.catchAll(() => Effect.succeed(false)), ) return yield* HttpServerResponse.setHeader( yield* HttpServerResponse.file(isValid ? source : path.join(dist, "index.html")), "Cache-Control", `public, max-age=${Duration.toSeconds("365 days")}, immutable` ) }) }) export const HttpAppDevelopment = Effect.provide(makeWebRpcRoute, WebRpcSerializationDevelopment).pipe( Effect.map(serveWebRpc => router.pipe( serveWebRpc, HttpServer.serve(flow( HttpMiddleware.logger, HttpMiddleware.xForwardedHeaders, )), HttpServer.withLogAddress, )), Layer.unwrapScoped, ) export const HttpAppProduction = Effect.all([ Effect.provide(makeWebRpcRoute, WebRpcSerializationProduction), makeProductionWebappMiddleware, ]).pipe( Effect.map(([serveWebRpc, serveProductionWebapp]) => router.pipe( serveWebRpc, serveProductionWebapp, HttpServer.serve(HttpMiddleware.xForwardedHeaders), HttpServer.withLogAddress, )), Layer.unwrapScoped, )