feat: api v1 routes for calendar lists and notes

This commit is contained in:
ginnoir
2026-07-04 19:03:08 -05:00
parent ea5d1d050c
commit d4304b005c
25 changed files with 1141 additions and 236 deletions
+6 -1
View File
@@ -18,7 +18,12 @@ function parseBearerToken(request: Request): string | null {
}
async function resolveSessionAuth(): Promise<ApiAuthContext | null> {
const session = await auth();
let session;
try {
session = await auth();
} catch {
return null;
}
if (!session?.user?.id) return null;
const [row] = await db
+49
View File
@@ -0,0 +1,49 @@
import { ZodError } from "zod";
import { requireApiAuth, type ApiAuthContext } from "@/lib/api-auth";
export function apiJson(data: unknown, status = 200): Response {
return new Response(JSON.stringify(data), {
status,
headers: { "Content-Type": "application/json" },
});
}
export function apiError(message: string, status: number): Response {
return apiJson({ error: message }, status);
}
const NOT_FOUND_PATTERN = /not found/i;
function mapApiError(err: unknown): Response {
if (err instanceof ZodError) {
const message = err.issues[0]?.message ?? "Validation error";
return apiError(message, 400);
}
if (err instanceof Error) {
if (NOT_FOUND_PATTERN.test(err.message)) {
return apiError(err.message, 404);
}
if (err.message === "Forbidden") {
return apiError(err.message, 403);
}
return apiError(err.message, 500);
}
return apiError("Internal server error", 500);
}
export { mapApiError };
export async function withApiHandler(
request: Request,
handler: (scope: ApiAuthContext, request: Request) => Promise<Response>,
): Promise<Response> {
try {
const scope = await requireApiAuth(request);
return await handler(scope, request);
} catch (err) {
if (err instanceof Response) return err;
return mapApiError(err);
}
}