{"version":3,"file":"verify.mjs","names":[],"sources":["../../../../../../src/astro/routes/api/auth/magic-link/verify.ts"],"sourcesContent":["/**\n * GET /_emdash/api/auth/magic-link/verify\n *\n * Verify a magic link token and create a session.\n * Tokens are single-use and expire after 15 minutes.\n */\n\nimport type { APIRoute } from \"astro\";\n\nexport const prerender = false;\n\nimport { verifyMagicLink, MagicLinkError } from \"@premium-cms/auth\";\nimport { createKyselyAdapter } from \"@premium-cms/auth/adapters/kysely\";\n\nimport { apiError } from \"#api/error.js\";\nimport { isSafeRedirect } from \"#api/redirect.js\";\n\nexport const GET: APIRoute = async ({ url, locals, session, redirect }) => {\n\tconst { emdash } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\t// Get token from query params\n\tconst token = url.searchParams.get(\"token\");\n\n\tif (!token) {\n\t\t// Redirect to login with error\n\t\treturn redirect(\"/_emdash/admin/login?error=missing_token\");\n\t}\n\n\ttry {\n\t\t// Verify the magic link token\n\t\tconst adapter = createKyselyAdapter(emdash.db);\n\t\tconst user = await verifyMagicLink(adapter, token);\n\n\t\t// Fire-and-forget cleanup of expired tokens -- prevents accumulation\n\t\tvoid adapter.deleteExpiredTokens().catch(() => {});\n\n\t\t// Create session\n\t\tif (session) {\n\t\t\tsession.set(\"user\", { id: user.id });\n\t\t}\n\n\t\t// Check for a stored redirect URL (from original request)\n\t\t// Validate redirect is a safe local path (prevent open redirect via //evil.com or /\\evil.com)\n\t\tconst rawRedirect = url.searchParams.get(\"redirect\");\n\t\tconst redirectUrl = isSafeRedirect(rawRedirect) ? rawRedirect : \"/_emdash/admin\";\n\n\t\t// Redirect to admin dashboard or original URL\n\t\treturn redirect(redirectUrl);\n\t} catch (error) {\n\t\tconsole.error(\"Magic link verify error:\", error);\n\n\t\t// Handle specific errors\n\t\tif (error instanceof MagicLinkError) {\n\t\t\tswitch (error.code) {\n\t\t\t\tcase \"invalid_token\":\n\t\t\t\t\treturn redirect(\"/_emdash/admin/login?error=invalid_link\");\n\t\t\t\tcase \"token_expired\":\n\t\t\t\t\treturn redirect(\"/_emdash/admin/login?error=link_expired\");\n\t\t\t\tcase \"user_not_found\":\n\t\t\t\t\treturn redirect(\"/_emdash/admin/login?error=user_not_found\");\n\t\t\t}\n\t\t}\n\n\t\t// Generic error\n\t\treturn redirect(\"/_emdash/admin/login?error=verification_failed\");\n\t}\n};\n"],"mappings":";;;;;;;;AASA,MAAa,YAAY;AAQzB,MAAa,MAAgB,OAAO,EAAE,KAAK,QAAQ,SAAS,eAAe;CAC1E,MAAM,EAAE,WAAW;AAEnB,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;CAIpE,MAAM,QAAQ,IAAI,aAAa,IAAI,QAAQ;AAE3C,KAAI,CAAC,MAEJ,QAAO,SAAS,2CAA2C;AAG5D,KAAI;EAEH,MAAM,UAAU,oBAAoB,OAAO,GAAG;EAC9C,MAAM,OAAO,MAAM,gBAAgB,SAAS,MAAM;AAGlD,EAAK,QAAQ,qBAAqB,CAAC,YAAY,GAAG;AAGlD,MAAI,QACH,SAAQ,IAAI,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC;EAKrC,MAAM,cAAc,IAAI,aAAa,IAAI,WAAW;AAIpD,SAAO,SAHa,eAAe,YAAY,GAAG,cAAc,iBAGpC;UACpB,OAAO;AACf,UAAQ,MAAM,4BAA4B,MAAM;AAGhD,MAAI,iBAAiB,eACpB,SAAQ,MAAM,MAAd;GACC,KAAK,gBACJ,QAAO,SAAS,0CAA0C;GAC3D,KAAK,gBACJ,QAAO,SAAS,0CAA0C;GAC3D,KAAK,iBACJ,QAAO,SAAS,4CAA4C;;AAK/D,SAAO,SAAS,iDAAiD"}