106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
import type { APIContext } from "./context.js";
|
|
import { LoggingHandlerPlugin } from "@orpc/experimental-pino";
|
|
import { RPCHandler } from "@orpc/server/fetch";
|
|
import { createDb } from "@reviq/db";
|
|
import { createLoggingEmailClient, createPostmarkClient } from "@reviq/emails";
|
|
import pino from "pino";
|
|
import {
|
|
BASE_URL,
|
|
DEFAULT_PORT,
|
|
DEFAULT_RP_NAME,
|
|
EMAIL_FROM,
|
|
getAllowedOrigins,
|
|
POSTMARK_API_KEY,
|
|
} from "./constants.js";
|
|
import { router } from "./router.js";
|
|
|
|
const logger = pino({
|
|
transport: {
|
|
target: "pino-pretty",
|
|
options: {
|
|
colorize: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
const databaseUrl = Bun.env.DATABASE_URL;
|
|
if (!databaseUrl) {
|
|
throw new Error("DATABASE_URL environment variable is required");
|
|
}
|
|
const db = createDb(databaseUrl);
|
|
|
|
// Create email client - use Postmark if API key is set, otherwise log to console
|
|
const emailClient = POSTMARK_API_KEY
|
|
? createPostmarkClient(POSTMARK_API_KEY)
|
|
: createLoggingEmailClient();
|
|
|
|
if (!POSTMARK_API_KEY) {
|
|
logger.info("POSTMARK_API_KEY not set - emails will be logged to console");
|
|
}
|
|
|
|
const handler = new RPCHandler(router, {
|
|
plugins: [
|
|
new LoggingHandlerPlugin({
|
|
logger,
|
|
logRequestResponse: true,
|
|
}),
|
|
],
|
|
});
|
|
|
|
const port = Bun.env.PORT ?? DEFAULT_PORT;
|
|
const allowedOrigins = getAllowedOrigins();
|
|
const rpName = Bun.env.RP_NAME ?? DEFAULT_RP_NAME;
|
|
|
|
Bun.serve({
|
|
port,
|
|
async fetch(request, server) {
|
|
const url = new URL(request.url);
|
|
|
|
if (url.pathname.startsWith("/api/v1/rpc")) {
|
|
// Build context for the request
|
|
const origin =
|
|
request.headers.get("origin") ?? `http://localhost:${port.toString()}`;
|
|
|
|
// Create response headers for setting cookies
|
|
const resHeaders = new Headers();
|
|
|
|
// Get client IP from Bun's server (fallback for when no proxy headers)
|
|
const socketInfo = server.requestIP(request);
|
|
const clientIP = socketInfo?.address ?? null;
|
|
|
|
const context: APIContext = {
|
|
db,
|
|
origin,
|
|
allowedOrigins,
|
|
rpName,
|
|
reqHeaders: request.headers,
|
|
resHeaders,
|
|
clientIP,
|
|
email: {
|
|
client: emailClient,
|
|
fromAddress: EMAIL_FROM,
|
|
baseUrl: BASE_URL,
|
|
},
|
|
};
|
|
|
|
const { response } = await handler.handle(request, {
|
|
prefix: "/api/v1/rpc",
|
|
context,
|
|
});
|
|
|
|
// Merge response headers (cookies) into the response
|
|
if (response) {
|
|
resHeaders.forEach((value, key) => {
|
|
response.headers.append(key, value);
|
|
});
|
|
}
|
|
|
|
return response ?? new Response("Not Found", { status: 404 });
|
|
}
|
|
|
|
return new Response("Not Found", { status: 404 });
|
|
},
|
|
});
|
|
|
|
logger.info({ port }, "API server running");
|