···1919const isProduction = process.env.NODE_ENV === "production";
20202121const environment = process.env.NODE_ENV;
2222+2223// Only compute git commit in development, use a constant in production to avoid process spawn
2324const commit = isProduction
2425 ? "production"
···9192const server = Bun.serve({
9293 port: process.env.PORT || 3000,
9394 reusePort: true,
9494- maxRequestBodySize: 1024 * 1024, // 1MB max request size
9595+ maxRequestBodySize: 1024 * 1024,
9596 routes: {
9697 "/": root,
9798 // Apply CORS to all API routes
+8-19
src/libs/cors.ts
···11/**
22 * CORS configuration for the application
33- * This adds support for Cloudflare Insights specifically
43 */
5465// Pre-defined CORS headers for better performance
···1110 Vary: "Origin",
1211};
13121414-// Allowed origins for CORS
1515-const ALLOWED_ORIGINS = [
1616- "https://static.cloudflareinsights.com",
1717- "https://cloudflareinsights.com",
1818-];
1313+// Allowed origins for CORS - can be expanded as needed
1414+const ALLOWED_ORIGINS: string[] = [];
19152016/**
2121- * Adds CORS headers to allow Cloudflare Insights
1717+ * Adds CORS headers to a response
2218 * @param response The response to add CORS headers to
2319 * @param origin The request origin to use for Access-Control-Allow-Origin
2420 * @returns A new response with added CORS headers
2521 */
2626-function addCloudflareInsightsCors(
2222+function addCorsHeaders(
2723 response: Response,
2824 origin: string,
2925): Response {
···5349function handleCorsPreflightRequest(req: Request): Response {
5450 const origin = req.headers.get("Origin");
55515656- // Fast path: if origin is not in allowed list, return minimal response
5757- if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
5252+ // If no origin or not in allowed list (if any are specified)
5353+ if (!origin || (ALLOWED_ORIGINS.length > 0 && !ALLOWED_ORIGINS.includes(origin))) {
5854 return new Response(null, { status: 204 });
5955 }
6056···73697470/**
7571 * Higher-order function that adds CORS support to a request handler
7676- * Specifically configured for Cloudflare Insights requests
7772 * @param handler The original request handler function
7873 * @returns A new handler function with CORS support added
7974 */
8075export function handleCORS(
8176 handler: (req: Request) => Response | Promise<Response>,
8277): (req: Request) => Promise<Response> {
8383- // Cache response for OPTIONS requests
8484- const cachedOptionsResponse = new Response(null, {
8585- status: 204,
8686- headers: CORS_HEADERS,
8787- });
8888-8978 return async (req: Request) => {
9079 // Fast path for OPTIONS - most common CORS request
9180 if (req.method === "OPTIONS") {
···9685 const origin = req.headers.get("Origin");
97869887 // Fast path for non-CORS requests
9999- if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
8888+ if (!origin || (ALLOWED_ORIGINS.length > 0 && !ALLOWED_ORIGINS.includes(origin))) {
10089 return handler(req);
10190 }
1029110392 // Process the request normally then add CORS headers
10493 const response = await handler(req);
105105- return addCloudflareInsightsCors(response, origin);
9494+ return addCorsHeaders(response, origin);
10695 };
10796}
+34
src/libs/headers/index.ts
···11+/**
22+ * Security headers for the application
33+ *
44+ * This module contains header configurations for Content Security Policy
55+ * and other security-related headers
66+ */
77+88+import type { HeadersInit } from "bun";
99+1010+// CSP directives to allow necessary resources while maintaining security
1111+export const contentSecurityPolicy =
1212+ "default-src 'self'; " +
1313+ "script-src 'self' https://cdn.jsdelivr.net 'unsafe-inline' 'unsafe-eval'; " +
1414+ "style-src 'self' https://cdn.jsdelivr.net 'unsafe-inline'; " +
1515+ "img-src 'self' https://cachet.dunkirk.sh https://emoji.slack-edge.com *.slack-edge.com data:; " +
1616+ "connect-src 'self'; " +
1717+ "frame-src 'self';";
1818+1919+// Standard security headers for all responses
2020+export const securityHeaders = {
2121+ "Content-Security-Policy": contentSecurityPolicy,
2222+ "Referrer-Policy": "strict-origin-when-cross-origin",
2323+ "X-Content-Type-Options": "nosniff",
2424+ "X-Frame-Options": "DENY",
2525+ "X-XSS-Protection": "1; mode=block",
2626+};
2727+2828+// Function to get headers for the main HTML page
2929+export function getHtmlResponseHeaders(): HeadersInit {
3030+ return {
3131+ "Content-Type": "text/html",
3232+ ...securityHeaders,
3333+ };
3434+}