import express from "express"; import compression from "compression"; import morgan from "morgan"; import { createRequestHandler } from "@remix-run/express"; import * as Sentry from "@sentry/node"; import config from "~/config/config.server"; import logger from "~/utils/logger.server"; import { adminMiddleware, setupBullBoard } from "./queues"; import { registerSentry, sentryLoadContext } from "./sentry-remix"; import { purgeRequireCache } from "./purge-require-cache"; const environment = process.env.NODE_ENV; if (config.sentry.dsn) { Sentry.init({ dsn: config.sentry.dsn, integrations: [new Sentry.Integrations.Http({ tracing: true })], tracesSampleRate: 1.0, environment, }); } const app = express(); app.use((req, res, next) => { res.set("X-Fly-Region", process.env.FLY_REGION ?? "unknown"); res.set("Strict-Transport-Security", `max-age=31536000; preload`); next(); }); // replay non-GET/HEAD/OPTIONS requests to the primary Fly.io region rather than read-only Postgres instances // learn more: https://fly.io/docs/getting-started/multi-region-databases/#replay-the-request app.all("*", (req, res, next) => { const { method, path: pathname } = req; const { PRIMARY_REGION, FLY_REGION } = process.env; const isMethodReplayable = !["GET", "OPTIONS", "HEAD"].includes(method); const isReadOnlyRegion = FLY_REGION && PRIMARY_REGION && FLY_REGION !== PRIMARY_REGION; const shouldReplay = isMethodReplayable && isReadOnlyRegion; if (!shouldReplay) { return next(); } const logInfo = { pathname, method, PRIMARY_REGION, FLY_REGION, }; logger.info("Replaying:", logInfo); res.set("fly-replay", `region=${PRIMARY_REGION}`); return res.sendStatus(409); }); app.disable("x-powered-by"); app.use( compression({ filter(req, res) { const contentTypeHeader = res.getHeader("Content-Type"); let contentType = ""; if (contentTypeHeader) { if (Array.isArray(contentTypeHeader)) { contentType = contentTypeHeader.join(" "); } else { contentType = String(contentTypeHeader); } } if (contentType.includes("text/event-stream")) { return false; } return true; }, }), ); // cache static and immutable assets app.use(express.static("public", { immutable: true, maxAge: "1y" })); // setup background queues and cron jobs app.use("/admin", adminMiddleware); app.use("/admin/queues", setupBullBoard().getRouter()); app.use(morgan("tiny")); app.all("*", (req, res, next) => { if (environment !== "production") { purgeRequireCache(); } return createRequestHandler({ build: registerSentry(require("../build")), mode: environment, getLoadContext: sentryLoadContext, })(req, res, next); }); const port = process.env.PORT || 3000; app.listen(port, () => { logger.info(`Server listening on port ${port}`); });