import { fail, redirect } from '@sveltejs/kit'; import { createPbClient } from '$lib/server/pocketbase'; import { setSessionCookie, clearActiveChild } from '$lib/server/session'; import { pbAdmin } from '$lib/server/pocketbase'; import { handleOf } from '@shared/slugify'; export const actions = { default: async (event) => { const fd = await event.request.formData(); const email = fd.get('email') as string; const password = fd.get('password') as string; if (!email || !password) { return fail(400, { error: 'Email and password required', email }); } let authResult: { token: string; record: any }; try { authResult = await createPbClient().collection('users').authWithPassword(email, password); } catch { return fail(400, { error: 'Invalid email or password', email }); } const user = authResult.record; if (!user.famId) { return fail(400, { error: 'No family linked to this account', email }); } setSessionCookie(event.cookies, authResult.token); // An explicit email/password login supersedes kid mode on a shared device. clearActiveChild(event.cookies); // Fam lookup with retries: right after a deploy/rebuild PB can blip and // a single failed fetch falls back to the raw fam ID in the URL // (/{famId}/...), which then persists via bookmarks/shortcuts. let fam: any = null; for (let i = 0; i < 4 && !fam; i++) { if (i > 0) await new Promise((r) => setTimeout(r, 500 * i)); fam = await pbAdmin.getOne('fams', user.famId).catch(() => null); } if (!fam) { return fail(503, { error: 'Family data is briefly unavailable (server restarting). Please try again.', email }); } const famSlug = fam.slug; // Parents (admins) land on the fam dashboard — no username in the URL. if (user.role === 'parent') { throw redirect(303, `/${famSlug}`); } // Children don't log in via email; this is just a safe fallback. const handle = handleOf(user.username || '') || user.name || email.split('@')[0]; throw redirect(303, `/${famSlug}/${handle}`); } };