import * as trpcExpress from "@trpc/server/adapters/express" import path from "path" import express from "express" import cors from "cors" import { prisma } from "./utils/prisma" import swaggerUi from "swagger-ui-express" import { createContext, router } from "./trpc" import { userRouter } from "./user/router" import { listRouter } from "./list/router" import { organizationRouter } from "./organization/router" import { subscriberRouter } from "./subscriber/router" import { templateRouter } from "./template/router" import { campaignRouter } from "./campaign/router" import { messageRouter } from "./message/router" import { settingsRouter } from "./settings/router" import swaggerSpec from "./swagger" import { apiRouter } from "./api/server" import { dashboardRouter } from "./dashboard/router" import { statsRouter } from "./stats/router" import { ONE_PX_PNG } from "./constants" const appRouter = router({ user: userRouter, list: listRouter, organization: organizationRouter, subscriber: subscriberRouter, template: templateRouter, campaign: campaignRouter, message: messageRouter, settings: settingsRouter, dashboard: dashboardRouter, stats: statsRouter, }) export type AppRouter = typeof appRouter export const app = express() app.use( cors({ origin: ["http://localhost:3000", "http://localhost:4173"], }) ) app.use(express.json()) app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)) app.get("/t/:id", async (req, res) => { try { const { id } = req.params const subscriberId = req.query.sid const trackedLink = await prisma.trackedLink.findUnique({ where: { id }, }) if (!trackedLink) { res.status(404).send("Link not found") return } res.redirect(trackedLink.url) if (subscriberId && typeof subscriberId === "string") { await prisma .$transaction(async (tx) => { // add a new click await tx.click.create({ data: { subscriberId, trackedLinkId: trackedLink.id, }, }) if (!trackedLink.campaignId) return const message = await tx.message.findFirst({ where: { campaignId: trackedLink.campaignId, subscriberId, status: { not: "CLICKED", }, }, }) if (!message) return await tx.message.update({ where: { id: message.id, }, data: { status: "CLICKED", }, }) }) .catch((error) => { console.error("Error updating message status", error) }) } } catch (error) { res.status(404).send("Link not found") } }) app.get("/img/:id/img.png", async (req, res) => { // Send pixel immediately const pixel = Buffer.from(ONE_PX_PNG, "base64") res.setHeader("Content-Type", "image/png") res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate") res.setHeader("Pragma", "no-cache") res.setHeader("Expires", "0") res.end(pixel) const id = req.params.id try { await prisma.$transaction(async (tx) => { const message = await tx.message.findUnique({ where: { id, Campaign: { openTracking: true, }, }, }) if (!message) { return } if (message.status !== "SENT") return await tx.message.update({ where: { id }, data: { status: "OPENED", }, }) }) } catch (error) { console.error("Error updating message status", error) } }) app.use("/api", apiRouter) app.use( "/trpc", trpcExpress.createExpressMiddleware({ router: appRouter, createContext, }) ) const staticPath = path.join(__dirname, "..", "..", "web", "dist") // serve SPA content app.use(express.static(staticPath)) app.get("*", (_, res) => { res.sendFile(path.join(staticPath, "index.html")) })