diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts index ac19a10..1679294 100644 --- a/src/api/auth/index.ts +++ b/src/api/auth/index.ts @@ -37,7 +37,9 @@ export const auth = betterAuth({ crossSubDomainCookies: { enabled: false, // Not subdomains, different domains entirely }, - cookieSameSite: "none", // CRITICAL: Allow cross-site cookies + defaultCookieAttributes: { + sameSite: "none", // CRITICAL: Allow cross-site cookies (Vercel <-> Railway) + }, }, emailAndPassword: { diff --git a/src/api/form-fields/controller.ts b/src/api/form-fields/controller.ts index bbcfda3..e4eeb52 100644 --- a/src/api/form-fields/controller.ts +++ b/src/api/form-fields/controller.ts @@ -8,6 +8,48 @@ import type { UpdateFieldContext, } from "../../types/form-fields"; +// Public endpoint - no authentication required +export async function getPublicFields({ + params, + set, +}: { + params: { formId: string }; + set: { status?: number | string }; +}) { + const formExists = await prisma.form.count({ + where: { id: params.formId, isPublished: true }, // Only published forms are public + }); + + if (formExists === 0) { + set.status = 404; + logger.warn(`Published form not found for formId: ${params.formId}`); + return { + success: false, + message: "Form not found or not published", + data: [], + }; + } + + const fields = await prisma.formFields.findMany({ + where: { formId: params.formId }, + }); + + if (fields.length === 0) { + logger.info(`No fields found for formId: ${params.formId}`); + return { + success: true, + data: [], + }; + } + + logger.info(`Found ${fields.length} fields for formId: ${params.formId}`); + return { + success: true, + data: fields, + }; +} + +// Authenticated endpoint export async function getAllFields({ params, set }: GetAllFieldsContext) { const formExists = await prisma.form.count({ where: { id: params.formId }, diff --git a/src/api/form-fields/routes.ts b/src/api/form-fields/routes.ts index 533784f..d530615 100644 --- a/src/api/form-fields/routes.ts +++ b/src/api/form-fields/routes.ts @@ -11,10 +11,19 @@ import { createField, deleteField, getAllFields, + getPublicFields, swapFields, updateField, } from "./controller"; +// Public routes (no auth required for viewing form fields) +export const publicFormFieldRoutes = new Elysia({ prefix: "/fields" }).get( + "/public/:formId", + getPublicFields, + getAllFieldsDTO, +); + +// Protected routes (require auth) export const formFieldRoutes = new Elysia({ prefix: "/fields" }) .use(requireAuth) .get("/:formId", getAllFields, getAllFieldsDTO) diff --git a/src/index.ts b/src/index.ts index d007e13..47b0835 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,10 @@ import { cors } from "@elysiajs/cors"; import { Elysia } from "elysia"; import { authRoutes } from "./api/auth/routes"; -import { formFieldRoutes } from "./api/form-fields/routes"; +import { + formFieldRoutes, + publicFormFieldRoutes, +} from "./api/form-fields/routes"; import { formResponseRoutes } from "./api/form-response/routes"; import { formRoutes, publicFormRoutes } from "./api/forms/routes"; import { logger } from "./logger/index"; @@ -57,6 +60,7 @@ const app = new Elysia() .get("/", () => "🦊 Elysia server started") .use(authRoutes) .use(publicFormRoutes) // Public routes first (no auth) + .use(publicFormFieldRoutes) // Public form fields (no auth) .use(formRoutes) .use(formFieldRoutes) .use(formResponseRoutes);