{"version":3,"file":"_name_.mjs","names":[],"sources":["../../../../../../../src/astro/routes/api/settings/backups/archives/[name].ts"],"sourcesContent":["/**\n * Backup archives — download / delete\n *\n * GET    /_emdash/api/settings/backups/archives/:name — download an archive.\n * DELETE /_emdash/api/settings/backups/archives/:name — delete an archive.\n *\n * `name` is validated against the strict archive-filename pattern before it\n * touches a storage key, so path traversal into other prefixes is impossible.\n */\n\nimport type { APIRoute } from \"astro\";\n\nimport { requirePerm } from \"#api/authorize.js\";\nimport { apiError, handleError, unwrapResult } from \"#api/error.js\";\nimport { ErrorCode } from \"#api/errors.js\";\nimport {\n\tBACKUP_STORAGE_PREFIX,\n\tdeleteBackupArchive,\n\tisValidArchiveName,\n} from \"#api/handlers/backup.js\";\n\nexport const prerender = false;\n\nexport const GET: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name ?? \"\";\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst denied = requirePerm(user, \"backups:manage\");\n\tif (denied) return denied;\n\n\tif (!emdash.storage) {\n\t\treturn apiError(\"STORAGE_NOT_CONFIGURED\", \"No storage backend is configured\", 503);\n\t}\n\n\tif (!isValidArchiveName(name)) {\n\t\treturn apiError(\"VALIDATION_ERROR\", \"Invalid archive name\", 400);\n\t}\n\n\ttry {\n\t\tconst result = await emdash.storage.download(`${BACKUP_STORAGE_PREFIX}${name}`);\n\t\treturn new Response(result.body, {\n\t\t\tstatus: 200,\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"Content-Disposition\": `attachment; filename=\"${name}\"`,\n\t\t\t\t\"Cache-Control\": \"private, no-store\",\n\t\t\t\t\"X-Content-Type-Options\": \"nosniff\",\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof Error && error.message.toLowerCase().includes(\"not found\")) {\n\t\t\treturn apiError(\"NOT_FOUND\", \"Archive not found\", 404);\n\t\t}\n\t\treturn handleError(error, \"Failed to download archive\", ErrorCode.BACKUP_DOWNLOAD_ERROR);\n\t}\n};\n\nexport const DELETE: APIRoute = async ({ params, locals }) => {\n\tconst { emdash, user } = locals;\n\tconst name = params.name ?? \"\";\n\n\tif (!emdash?.db) {\n\t\treturn apiError(\"NOT_CONFIGURED\", \"EmDash is not initialized\", 500);\n\t}\n\n\tconst denied = requirePerm(user, \"backups:manage\");\n\tif (denied) return denied;\n\n\tif (!emdash.storage) {\n\t\treturn apiError(\"STORAGE_NOT_CONFIGURED\", \"No storage backend is configured\", 503);\n\t}\n\n\treturn unwrapResult(await deleteBackupArchive(emdash.storage, name));\n};\n"],"mappings":";;;;;;;;;;AAqBA,MAAa,YAAY;AAEzB,MAAa,MAAgB,OAAO,EAAE,QAAQ,aAAa;CAC1D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO,QAAQ;AAE5B,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;CAGpE,MAAM,SAAS,YAAY,MAAM,iBAAiB;AAClD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,OAAO,QACX,QAAO,SAAS,0BAA0B,oCAAoC,IAAI;AAGnF,KAAI,CAAC,mBAAmB,KAAK,CAC5B,QAAO,SAAS,oBAAoB,wBAAwB,IAAI;AAGjE,KAAI;EACH,MAAM,SAAS,MAAM,OAAO,QAAQ,SAAS,GAAG,wBAAwB,OAAO;AAC/E,SAAO,IAAI,SAAS,OAAO,MAAM;GAChC,QAAQ;GACR,SAAS;IACR,gBAAgB;IAChB,uBAAuB,yBAAyB,KAAK;IACrD,iBAAiB;IACjB,0BAA0B;IAC1B;GACD,CAAC;UACM,OAAO;AACf,MAAI,iBAAiB,SAAS,MAAM,QAAQ,aAAa,CAAC,SAAS,YAAY,CAC9E,QAAO,SAAS,aAAa,qBAAqB,IAAI;AAEvD,SAAO,YAAY,OAAO,8BAA8B,UAAU,sBAAsB;;;AAI1F,MAAa,SAAmB,OAAO,EAAE,QAAQ,aAAa;CAC7D,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,OAAO,OAAO,QAAQ;AAE5B,KAAI,CAAC,QAAQ,GACZ,QAAO,SAAS,kBAAkB,6BAA6B,IAAI;CAGpE,MAAM,SAAS,YAAY,MAAM,iBAAiB;AAClD,KAAI,OAAQ,QAAO;AAEnB,KAAI,CAAC,OAAO,QACX,QAAO,SAAS,0BAA0B,oCAAoC,IAAI;AAGnF,QAAO,aAAa,MAAM,oBAAoB,OAAO,SAAS,KAAK,CAAC"}