{"version":3,"file":"send-recovery.mjs","names":[],"sources":["../../../../../../../src/astro/routes/api/admin/users/[id]/send-recovery.ts"],"sourcesContent":["/**\n * Send recovery link endpoint\n *\n * POST /_emdash/api/admin/users/:id/send-recovery\n *\n * Admin-initiated account recovery — sends a recovery magic link to the user's email.\n */\n\nimport { sendMagicLink, type MagicLinkConfig } from \"@premium-cms/auth\";\nimport { createKyselyAdapter } from \"@premium-cms/auth/adapters/kysely\";\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, apiSuccess, handleError } from \"#api/error.js\";\nimport { getSiteBaseUrl } from \"#api/site-url.js\";\nimport { OptionsRepository } from \"#db/repositories/options.js\";\n\nexport const prerender = false;\n\nexport const POST: APIRoute = async ({ request, params, locals }) => {\n\tconst { emdash, user } = locals;\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"Database not configured\", 500);\n\t}\n\n\tconst denied = requirePerm(user, \"users:manage\");\n\tif (denied) return denied;\n\n\tconst { id } = params;\n\n\tif (!id) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"User ID required\", 400);\n\t}\n\n\ttry {\n\t\tconst adapter = createKyselyAdapter(emdash.db);\n\n\t\t// Verify target user exists\n\t\tconst targetUser = await adapter.getUserById(id);\n\t\tif (!targetUser) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"User not found\", 404);\n\t\t}\n\n\t\t// Check if email pipeline is available\n\t\tif (!emdash.email?.isAvailable()) {\n\t\t\treturn apiError(\n\t\t\t\t\"EMAIL_NOT_CONFIGURED\",\n\t\t\t\t\"Email is not configured. Recovery links require an email provider.\",\n\t\t\t\t503,\n\t\t\t);\n\t\t}\n\n\t\t// Build config using the configured site URL, stored option as fallback (not request Host header)\n\t\tconst options = new OptionsRepository(emdash.db);\n\t\tconst baseUrl = await getSiteBaseUrl(emdash.db, request, emdash.config);\n\t\tconst siteName = (await options.get<string>(\"emdash:site_title\")) ?? \"EmDash\";\n\n\t\tconst config: MagicLinkConfig = {\n\t\t\tbaseUrl,\n\t\t\tsiteName,\n\t\t\temail: (message) => emdash.email!.send(message, \"system\"),\n\t\t};\n\n\t\t// Send recovery link\n\t\tawait sendMagicLink(config, adapter, targetUser.email, \"recovery\");\n\n\t\treturn apiSuccess({ success: true, message: \"Recovery link sent\" });\n\t} catch (error) {\n\t\treturn handleError(error, \"Failed to send recovery link\", \"RECOVERY_SEND_ERROR\");\n\t}\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,MAAa,YAAY;AAEzB,MAAa,OAAiB,OAAO,EAAE,SAAS,QAAQ,aAAa;CACpE,MAAM,EAAE,QAAQ,SAAS;AAEzB,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,2BAA2B,IAAI;CAGlE,MAAM,SAAS,YAAY,MAAM,eAAe;AAChD,KAAI,OAAQ,QAAO;CAEnB,MAAM,EAAE,OAAO;AAEf,KAAI,CAAC,GACJ,QAAO,SAAS,oBAAoB,oBAAoB,IAAI;AAG7D,KAAI;EACH,MAAM,UAAU,oBAAoB,OAAO,GAAG;EAG9C,MAAM,aAAa,MAAM,QAAQ,YAAY,GAAG;AAChD,MAAI,CAAC,WACJ,QAAO,SAAS,aAAa,kBAAkB,IAAI;AAIpD,MAAI,CAAC,OAAO,OAAO,aAAa,CAC/B,QAAO,SACN,wBACA,sEACA,IACA;EAIF,MAAM,UAAU,IAAI,kBAAkB,OAAO,GAAG;AAWhD,QAAM,cAP0B;GAC/B,SAJe,MAAM,eAAe,OAAO,IAAI,SAAS,OAAO,OAAO;GAKtE,UAJiB,MAAM,QAAQ,IAAY,oBAAoB,IAAK;GAKpE,QAAQ,YAAY,OAAO,MAAO,KAAK,SAAS,SAAS;GACzD,EAG2B,SAAS,WAAW,OAAO,WAAW;AAElE,SAAO,WAAW;GAAE,SAAS;GAAM,SAAS;GAAsB,CAAC;UAC3D,OAAO;AACf,SAAO,YAAY,OAAO,gCAAgC,sBAAsB"}