🪻 distributed transcription service thistle.dunkirk.sh

feat: make bun work in dev mode only in dev

dunkirk.sh a8e4ff56 39544f38

verified
Changed files
+41 -31
src
+41 -31
src/index.ts
···
email: string,
): Promise<void> {
// Skip Polar sync in test mode
-
if (process.env.NODE_ENV === "test" || process.env.SKIP_POLAR_SYNC === "true") {
+
if (
+
process.env.NODE_ENV === "test" ||
+
process.env.SKIP_POLAR_SYNC === "true"
+
) {
return;
}
···
);
const server = Bun.serve({
-
port: process.env.NODE_ENV === "test"
-
? 3001
-
: (process.env.PORT ? Number.parseInt(process.env.PORT, 10) : 3000),
+
port:
+
process.env.NODE_ENV === "test"
+
? 3001
+
: process.env.PORT
+
? Number.parseInt(process.env.PORT, 10)
+
: 3000,
idleTimeout: 120, // 120 seconds for SSE connections
routes: {
"/": indexHTML,
···
role: user.role,
has_subscription: !!subscription,
email_verified: isEmailVerified(user.id),
-
email_notifications_enabled: prefs?.email_notifications_enabled === 1,
+
email_notifications_enabled:
+
prefs?.email_notifications_enabled === 1,
});
} catch (err) {
return handleError(err);
···
try {
const sessionId = getSessionFromRequest(req);
if (!sessionId) {
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
+
return Response.json(
+
{ error: "Not authenticated" },
+
{ status: 401 },
+
);
const user = getUserBySession(sessionId);
if (!user) {
···
try {
const currentSessionId = getSessionFromRequest(req);
if (!currentSessionId) {
-
return Response.json({ error: "Not authenticated" }, { status: 401 });
+
return Response.json(
+
{ error: "Not authenticated" },
+
{ status: 401 },
+
);
const user = getUserBySession(currentSessionId);
if (!user) {
···
const body = await req.json();
const { password } = body;
if (!password) {
-
return Response.json({ error: "Password required" }, { status: 400 });
+
return Response.json(
+
{ error: "Password required" },
+
{ status: 400 },
+
);
// Validate password format (client-side hashed PBKDF2)
const passwordValidation = validatePasswordHash(password);
···
// Allow access if: owner, admin, or enrolled in the class
if (!isOwner && !isAdmin && !isClassMember) {
-
return Response.json(
-
{ error: "Forbidden" },
-
{ status: 403 },
-
);
+
return Response.json({ error: "Forbidden" }, { status: 403 });
// Require subscription only if accessing own transcription (not class)
···
// Allow access if: owner, admin, or enrolled in the class
if (!isOwner && !isAdmin && !isClassMember) {
-
return Response.json(
-
{ error: "Forbidden" },
-
{ status: 403 },
-
);
+
return Response.json({ error: "Forbidden" }, { status: 403 });
// Require subscription only if accessing own transcription (not class)
···
// Allow access if: owner, admin, or enrolled in the class
if (!isOwner && !isAdmin && !isClassMember) {
-
return Response.json(
-
{ error: "Forbidden" },
-
{ status: 403 },
-
);
+
return Response.json({ error: "Forbidden" }, { status: 403 });
// Require subscription only if accessing own transcription (not class)
···
// Verify meeting exists
const existingMeeting = getMeetingById(meetingId);
if (!existingMeeting) {
-
return Response.json({ error: "Meeting not found" }, { status: 404 });
+
return Response.json(
+
{ error: "Meeting not found" },
+
{ status: 404 },
+
);
updateMeetingTime(meetingId, label);
···
// Verify meeting exists
const existingMeeting = getMeetingById(meetingId);
if (!existingMeeting) {
-
return Response.json({ error: "Meeting not found" }, { status: 404 });
+
return Response.json(
+
{ error: "Meeting not found" },
+
{ status: 404 },
+
);
deleteMeetingTime(meetingId);
···
},
},
},
-
development: {
-
hmr: true,
-
console: true,
-
},
+
development: process.env.NODE_ENV === "dev",
fetch(req, server) {
const response = server.fetch(req);
-
+
// Add security headers to all responses
if (response instanceof Response) {
const headers = new Headers(response.headers);
···
headers.set("X-Content-Type-Options", "nosniff");
headers.set("X-Frame-Options", "DENY");
headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
-
+
// Set CSP that allows inline styles with unsafe-inline (needed for Lit components)
// and script-src 'self' for bundled scripts
headers.set(
"Content-Security-Policy",
-
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://hostedboringavatars.vercel.app; font-src 'self'; connect-src 'self'; form-action 'self'; base-uri 'self'; frame-ancestors 'none'; object-src 'none';"
+
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://hostedboringavatars.vercel.app; font-src 'self'; connect-src 'self'; form-action 'self'; base-uri 'self'; frame-ancestors 'none'; object-src 'none';",
);
-
+
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
});
-
+
return response;
},
});