From b975f8e9b948a5dd004d2516fb0c47eb12babcb8 Mon Sep 17 00:00:00 2001 From: space Date: Sat, 25 Jul 2026 00:20:48 +0200 Subject: [PATCH] chore: add .gitignore, remove dist from tracking Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 8 + backend/dist/index.js | 121 --- backend/dist/index.js.map | 7 - backend/dist/lib/adminSettings.js | 36 - backend/dist/lib/adminSettings.js.map | 7 - backend/dist/lib/db.js | 33 - backend/dist/lib/db.js.map | 7 - backend/dist/lib/encryption.js | 50 -- backend/dist/lib/encryption.js.map | 7 - backend/dist/lib/env.js | 58 -- backend/dist/lib/env.js.map | 7 - backend/dist/lib/errors.js | 37 - backend/dist/lib/errors.js.map | 7 - backend/dist/lib/logger.js | 49 -- backend/dist/lib/logger.js.map | 7 - backend/dist/lib/middlewares/auth.js | 88 -- backend/dist/lib/middlewares/auth.js.map | 7 - backend/dist/lib/middlewares/cors.js | 40 - backend/dist/lib/middlewares/cors.js.map | 7 - backend/dist/lib/middlewares/main.js | 38 - backend/dist/lib/middlewares/main.js.map | 7 - backend/dist/lib/response.js | 64 -- backend/dist/lib/response.js.map | 7 - backend/dist/routes/api/admin.js | 192 ----- backend/dist/routes/api/admin.js.map | 7 - backend/dist/routes/api/previews.js | 153 ---- backend/dist/routes/api/previews.js.map | 7 - backend/dist/routes/api/repos.js | 180 ---- backend/dist/routes/api/repos.js.map | 7 - backend/dist/routes/api/user.js | 204 ----- backend/dist/routes/api/user.js.map | 7 - backend/dist/routes/auth.js | 161 ---- backend/dist/routes/auth.js.map | 7 - backend/dist/routes/webhook.js | 279 ------- backend/dist/routes/webhook.js.map | 7 - backend/dist/services/deploy.js | 440 ---------- backend/dist/services/deploy.js.map | 7 - backend/dist/services/ec2.js | 244 ------ backend/dist/services/ec2.js.map | 7 - backend/dist/services/gitea.js | 170 ---- backend/dist/services/gitea.js.map | 7 - backend/dist/services/orphanCleanup.js | 74 -- backend/dist/services/orphanCleanup.js.map | 7 - backend/dist/services/ssh.js | 115 --- backend/dist/services/ssh.js.map | 7 - backend/dist/workers/cronWorker.js | 100 --- backend/dist/workers/cronWorker.js.map | 7 - backend/dist/workers/jobWorker.js | 114 --- backend/dist/workers/jobWorker.js.map | 7 - frontend/dist/assets/index-BhM-WgUO.js | 905 --------------------- frontend/dist/assets/index-CA1FHrdL.css | 1 - frontend/dist/index.html | 14 - 52 files changed, 8 insertions(+), 4128 deletions(-) create mode 100644 .gitignore delete mode 100644 backend/dist/index.js delete mode 100644 backend/dist/index.js.map delete mode 100644 backend/dist/lib/adminSettings.js delete mode 100644 backend/dist/lib/adminSettings.js.map delete mode 100644 backend/dist/lib/db.js delete mode 100644 backend/dist/lib/db.js.map delete mode 100644 backend/dist/lib/encryption.js delete mode 100644 backend/dist/lib/encryption.js.map delete mode 100644 backend/dist/lib/env.js delete mode 100644 backend/dist/lib/env.js.map delete mode 100644 backend/dist/lib/errors.js delete mode 100644 backend/dist/lib/errors.js.map delete mode 100644 backend/dist/lib/logger.js delete mode 100644 backend/dist/lib/logger.js.map delete mode 100644 backend/dist/lib/middlewares/auth.js delete mode 100644 backend/dist/lib/middlewares/auth.js.map delete mode 100644 backend/dist/lib/middlewares/cors.js delete mode 100644 backend/dist/lib/middlewares/cors.js.map delete mode 100644 backend/dist/lib/middlewares/main.js delete mode 100644 backend/dist/lib/middlewares/main.js.map delete mode 100644 backend/dist/lib/response.js delete mode 100644 backend/dist/lib/response.js.map delete mode 100644 backend/dist/routes/api/admin.js delete mode 100644 backend/dist/routes/api/admin.js.map delete mode 100644 backend/dist/routes/api/previews.js delete mode 100644 backend/dist/routes/api/previews.js.map delete mode 100644 backend/dist/routes/api/repos.js delete mode 100644 backend/dist/routes/api/repos.js.map delete mode 100644 backend/dist/routes/api/user.js delete mode 100644 backend/dist/routes/api/user.js.map delete mode 100644 backend/dist/routes/auth.js delete mode 100644 backend/dist/routes/auth.js.map delete mode 100644 backend/dist/routes/webhook.js delete mode 100644 backend/dist/routes/webhook.js.map delete mode 100644 backend/dist/services/deploy.js delete mode 100644 backend/dist/services/deploy.js.map delete mode 100644 backend/dist/services/ec2.js delete mode 100644 backend/dist/services/ec2.js.map delete mode 100644 backend/dist/services/gitea.js delete mode 100644 backend/dist/services/gitea.js.map delete mode 100644 backend/dist/services/orphanCleanup.js delete mode 100644 backend/dist/services/orphanCleanup.js.map delete mode 100644 backend/dist/services/ssh.js delete mode 100644 backend/dist/services/ssh.js.map delete mode 100644 backend/dist/workers/cronWorker.js delete mode 100644 backend/dist/workers/cronWorker.js.map delete mode 100644 backend/dist/workers/jobWorker.js delete mode 100644 backend/dist/workers/jobWorker.js.map delete mode 100644 frontend/dist/assets/index-BhM-WgUO.js delete mode 100644 frontend/dist/assets/index-CA1FHrdL.css delete mode 100644 frontend/dist/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..457dd706 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +backend/dist/ +frontend/dist/ +.env +*.env.local +*.log +.DS_Store +Thumbs.db diff --git a/backend/dist/index.js b/backend/dist/index.js deleted file mode 100644 index 2e4aaf11..00000000 --- a/backend/dist/index.js +++ /dev/null @@ -1,121 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var index_exports = {}; -__export(index_exports, { - server: () => server -}); -module.exports = __toCommonJS(index_exports); -var import_env = require("./lib/env"); -var import_rjweb_server = require("rjweb-server"); -var import_runtime_node = require("@rjweb/runtime-node"); -var import_node_fs = require("node:fs"); -var import_path = require("path"); -var import_db = require("./lib/db"); -var import_logger = require("./lib/logger"); -var import_cors = require("./lib/middlewares/cors"); -var import_main = require("./lib/middlewares/main"); -var import_auth = require("./lib/middlewares/auth"); -var import_response = require("./lib/response"); -var import_errors = require("./lib/errors"); -var import_jobWorker = require("./workers/jobWorker"); -var import_cronWorker = require("./workers/cronWorker"); -var import_adminSettings = require("./lib/adminSettings"); -var import_orphanCleanup = require("./services/orphanCleanup"); -var import_auth2 = require("./routes/auth"); -var import_webhook = require("./routes/webhook"); -var import_user = require("./routes/api/user"); -var import_repos = require("./routes/api/repos"); -var import_previews = require("./routes/api/previews"); -var import_admin = require("./routes/api/admin"); -const uiBuildPath = (0, import_path.join)(__dirname, "../../frontend/dist"); -const uiIndexPath = (0, import_path.join)(uiBuildPath, "index.html"); -const hasUiBuild = (0, import_node_fs.existsSync)(uiBuildPath); -const server = new import_rjweb_server.Server( - import_runtime_node.Runtime, - { - port: import_env.env.PORT, - bind: "0.0.0.0", - version: false, - performance: { lastModified: false, eTag: false }, - logging: { warn: true, debug: false, error: true } - }, - [ - import_cors.corsMiddleware.use({}), - import_main.mainMiddleware.use({}), - import_auth.authResolutionMiddleware.use({}), - import_auth.authEnforcementMiddleware.use({}) - ] -); -server.path( - "/api/auth", - (path) => path.http("POST", "/login", (http) => http.onRequest(import_auth2.loginHandler)).http("POST", "/logout", (http) => http.onRequest(import_auth2.logoutHandler)).http("GET", "/me", (http) => http.onRequest(import_auth2.meHandler)).http("GET", "/setup-status", (http) => http.onRequest(import_auth2.setupStatusHandler)).http("POST", "/first-user", (http) => http.onRequest(import_auth2.firstUserHandler)) -); -server.path( - "/webhook", - (path) => path.http("POST", "/:userId", (http) => http.onRequest(import_webhook.webhookHandler)) -); -server.path( - "/api/user", - (path) => path.http("GET", "/settings", (http) => http.onRequest(import_user.getUserSettings)).http("PATCH", "/username", (http) => http.onRequest(import_user.updateUsername)).http("PATCH", "/password", (http) => http.onRequest(import_user.updatePassword)).http("PUT", "/gitea", (http) => http.onRequest(import_user.updateGitea)).http("PUT", "/aws", (http) => http.onRequest(import_user.updateAws)).http("GET", "/webhook-secret", (http) => http.onRequest(import_user.getWebhookSecret)).http("POST", "/webhook-secret/regenerate", (http) => http.onRequest(import_user.regenerateWebhookSecret)) -); -server.path( - "/api/repos", - (path) => path.http("GET", "/", (http) => http.onRequest(import_repos.listRepos)).http("POST", "/config", (http) => http.onRequest(import_repos.saveRepoConfig)).http("POST", "/toggle", (http) => http.onRequest(import_repos.toggleRepoEnabled)).http("GET", "/:owner/:repo/config", (http) => http.onRequest(import_repos.getRepoConfig)) -); -server.path( - "/api/previews", - (path) => path.http("GET", "/", (http) => http.onRequest(import_previews.listPreviews)).http("GET", "/:id", (http) => http.onRequest(import_previews.getPreview)).http("POST", "/:id/stop", (http) => http.onRequest(import_previews.stopPreviewRoute)).ws( - "/:id/logs", - (ws) => ws.onOpen(import_previews.previewLogsWs).onMessage(async () => { - }).onClose(async () => { - }) - ) -); -server.path( - "/api/admin", - (path) => path.http("GET", "/users", (http) => http.onRequest(import_admin.listUsers)).http("POST", "/users", (http) => http.onRequest(import_admin.createUser)).http("PATCH", "/users/:id", (http) => http.onRequest(import_admin.updateUser)).http("DELETE", "/users/:id", (http) => http.onRequest(import_admin.deleteUser)).http("GET", "/settings", (http) => http.onRequest(import_admin.getSettings)).http("PUT", "/settings", (http) => http.onRequest(import_admin.updateSettings)).http("GET", "/previews", (http) => http.onRequest(import_admin.adminListPreviews)).http("POST", "/previews/:id/stop", (http) => http.onRequest(import_admin.adminStopPreview)) -); -if (hasUiBuild) { - server.path("/", (path) => path.static(uiBuildPath)); -} -server.notFound(async (ctr) => { - const STATIC_EXT = /\.(js|mjs|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|json|txt|xml|webp|avif)(\?.*)?$/i; - if (!ctr.url.path.startsWith("/api") && !STATIC_EXT.test(ctr.url.path) && (0, import_node_fs.existsSync)(uiIndexPath)) { - return ctr.status(200).printFile(uiIndexPath, { addTypes: true }); - } - return (0, import_response.makeResponse)({ ctr, content: { code: import_errors.ERROR_MESSAGES.NOT_FOUND.code, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); -}); -server.error("httpRequest", async (ctr, error) => { - import_logger.logger.error(error, "Unhandled HTTP request error"); - return (0, import_response.makeResponse)({ ctr, content: { code: import_errors.ERROR_MESSAGES.INTERNAL_SERVER_ERROR.code } }); -}); -server.start().then(async (port) => { - await import_db.prisma.$connect(); - import_logger.logger.info({ port }, "PP backend running"); - await (0, import_adminSettings.getAdminSettings)(); - (0, import_jobWorker.startJobWorker)(); - (0, import_cronWorker.startCronWorkers)(); - (0, import_orphanCleanup.runOrphanCleanup)().catch((e) => import_logger.logger.warn(e, "Orphan cleanup error")); - import_logger.logger.info("All workers started"); -}).catch((err) => import_logger.logger.error(err, "Server failed to start")); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - server -}); -//# sourceMappingURL=index.js.map diff --git a/backend/dist/index.js.map b/backend/dist/index.js.map deleted file mode 100644 index 935bd901..00000000 --- a/backend/dist/index.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/index.ts"], - "sourcesContent": ["import { env } from \"./lib/env\";\nimport { Server, Cookie } from \"rjweb-server\";\nimport { Runtime } from \"@rjweb/runtime-node\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"path\";\nimport { prisma } from \"./lib/db\";\nimport { logger } from \"./lib/logger\";\nimport { corsMiddleware } from \"./lib/middlewares/cors\";\nimport { mainMiddleware } from \"./lib/middlewares/main\";\nimport { authResolutionMiddleware, authEnforcementMiddleware } from \"./lib/middlewares/auth\";\nimport { makeResponse } from \"./lib/response\";\nimport { ERROR_MESSAGES } from \"./lib/errors\";\nimport { startJobWorker } from \"./workers/jobWorker\";\nimport { startCronWorkers } from \"./workers/cronWorker\";\nimport { getAdminSettings } from \"./lib/adminSettings\";\nimport { runOrphanCleanup } from \"./services/orphanCleanup\";\n\nimport { loginHandler, logoutHandler, meHandler, setupStatusHandler, firstUserHandler } from \"./routes/auth\";\nimport { webhookHandler } from \"./routes/webhook\";\nimport { getUserSettings, updateUsername, updatePassword, updateGitea, updateAws, getWebhookSecret, regenerateWebhookSecret } from \"./routes/api/user\";\nimport { listRepos, saveRepoConfig, toggleRepoEnabled, getRepoConfig } from \"./routes/api/repos\";\nimport { listPreviews, getPreview, stopPreviewRoute, previewLogsWs } from \"./routes/api/previews\";\nimport { listUsers, createUser, updateUser, deleteUser, getSettings, updateSettings, adminListPreviews, adminStopPreview } from \"./routes/api/admin\";\n\nconst uiBuildPath = join(__dirname, \"../../frontend/dist\");\nconst uiIndexPath = join(uiBuildPath, \"index.html\");\nconst hasUiBuild = existsSync(uiBuildPath);\n\nexport const server = new Server(\n Runtime,\n {\n port: env.PORT,\n bind: \"0.0.0.0\",\n version: false,\n performance: { lastModified: false, eTag: false },\n logging: { warn: true, debug: false, error: true },\n },\n [\n corsMiddleware.use({}),\n mainMiddleware.use({}),\n authResolutionMiddleware.use({}),\n authEnforcementMiddleware.use({}),\n ],\n);\n\n// Auth\nserver.path(\"/api/auth\", (path) => path\n .http(\"POST\", \"/login\", (http) => http.onRequest(loginHandler))\n .http(\"POST\", \"/logout\", (http) => http.onRequest(logoutHandler))\n .http(\"GET\", \"/me\", (http) => http.onRequest(meHandler))\n .http(\"GET\", \"/setup-status\", (http) => http.onRequest(setupStatusHandler))\n .http(\"POST\", \"/first-user\", (http) => http.onRequest(firstUserHandler))\n);\n\n// Webhook\nserver.path(\"/webhook\", (path) => path\n .http(\"POST\", \"/:userId\", (http) => http.onRequest(webhookHandler))\n);\n\n// User settings\nserver.path(\"/api/user\", (path) => path\n .http(\"GET\", \"/settings\", (http) => http.onRequest(getUserSettings))\n .http(\"PATCH\", \"/username\", (http) => http.onRequest(updateUsername))\n .http(\"PATCH\", \"/password\", (http) => http.onRequest(updatePassword))\n .http(\"PUT\", \"/gitea\", (http) => http.onRequest(updateGitea))\n .http(\"PUT\", \"/aws\", (http) => http.onRequest(updateAws))\n .http(\"GET\", \"/webhook-secret\", (http) => http.onRequest(getWebhookSecret))\n .http(\"POST\", \"/webhook-secret/regenerate\", (http) => http.onRequest(regenerateWebhookSecret))\n);\n\n// Repos\nserver.path(\"/api/repos\", (path) => path\n .http(\"GET\", \"/\", (http) => http.onRequest(listRepos))\n .http(\"POST\", \"/config\", (http) => http.onRequest(saveRepoConfig))\n .http(\"POST\", \"/toggle\", (http) => http.onRequest(toggleRepoEnabled))\n .http(\"GET\", \"/:owner/:repo/config\", (http) => http.onRequest(getRepoConfig))\n);\n\n// Previews\nserver.path(\"/api/previews\", (path) => path\n .http(\"GET\", \"/\", (http) => http.onRequest(listPreviews))\n .http(\"GET\", \"/:id\", (http) => http.onRequest(getPreview))\n .http(\"POST\", \"/:id/stop\", (http) => http.onRequest(stopPreviewRoute))\n .ws(\"/:id/logs\", (ws) => ws\n .onOpen(previewLogsWs)\n .onMessage(async () => {})\n .onClose(async () => {})\n )\n);\n\n// Admin\nserver.path(\"/api/admin\", (path) => path\n .http(\"GET\", \"/users\", (http) => http.onRequest(listUsers))\n .http(\"POST\", \"/users\", (http) => http.onRequest(createUser))\n .http(\"PATCH\", \"/users/:id\", (http) => http.onRequest(updateUser))\n .http(\"DELETE\", \"/users/:id\", (http) => http.onRequest(deleteUser))\n .http(\"GET\", \"/settings\", (http) => http.onRequest(getSettings))\n .http(\"PUT\", \"/settings\", (http) => http.onRequest(updateSettings))\n .http(\"GET\", \"/previews\", (http) => http.onRequest(adminListPreviews))\n .http(\"POST\", \"/previews/:id/stop\", (http) => http.onRequest(adminStopPreview))\n);\n\n// Static UI\nif (hasUiBuild) {\n server.path(\"/\", (path) => path.static(uiBuildPath));\n}\n\nserver.notFound(async (ctr) => {\n const STATIC_EXT = /\\.(js|mjs|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot|map|json|txt|xml|webp|avif)(\\?.*)?$/i;\n if (!ctr.url.path.startsWith(\"/api\") && !STATIC_EXT.test(ctr.url.path) && existsSync(uiIndexPath)) {\n return ctr.status(200).printFile(uiIndexPath, { addTypes: true });\n }\n return makeResponse({ ctr, content: { code: ERROR_MESSAGES.NOT_FOUND.code, message: ERROR_MESSAGES.NOT_FOUND.message } });\n});\n\nserver.error(\"httpRequest\", async (ctr, error) => {\n logger.error(error, \"Unhandled HTTP request error\");\n return makeResponse({ ctr, content: { code: ERROR_MESSAGES.INTERNAL_SERVER_ERROR.code } });\n});\n\nserver\n .start()\n .then(async (port) => {\n await prisma.$connect();\n logger.info({ port }, \"PP backend running\");\n await getAdminSettings();\n startJobWorker();\n startCronWorkers();\n runOrphanCleanup().catch(e => logger.warn(e, \"Orphan cleanup error\"));\n logger.info(\"All workers started\");\n })\n .catch((err) => logger.error(err, \"Server failed to start\"));\n"], - "mappings": "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", - "names": ["import_auth"] -} diff --git a/backend/dist/lib/adminSettings.js b/backend/dist/lib/adminSettings.js deleted file mode 100644 index f5faea37..00000000 --- a/backend/dist/lib/adminSettings.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var adminSettings_exports = {}; -__export(adminSettings_exports, { - getAdminSettings: () => getAdminSettings -}); -module.exports = __toCommonJS(adminSettings_exports); -var import_db = require("./db"); -async function getAdminSettings() { - let settings = await import_db.prisma.adminSettings.findUnique({ where: { id: 1 } }); - if (!settings) { - settings = await import_db.prisma.adminSettings.create({ data: { id: 1 } }); - } - return settings; -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - getAdminSettings -}); -//# sourceMappingURL=adminSettings.js.map diff --git a/backend/dist/lib/adminSettings.js.map b/backend/dist/lib/adminSettings.js.map deleted file mode 100644 index 0acef296..00000000 --- a/backend/dist/lib/adminSettings.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/adminSettings.ts"], - "sourcesContent": ["import { prisma } from \"./db\";\n\nexport async function getAdminSettings() {\n let settings = await prisma.adminSettings.findUnique({ where: { id: 1 } });\n if (!settings) {\n settings = await prisma.adminSettings.create({ data: { id: 1 } });\n }\n return settings;\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAuB;AAEvB,eAAsB,mBAAmB;AACvC,MAAI,WAAW,MAAM,iBAAO,cAAc,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;AACzE,MAAI,CAAC,UAAU;AACb,eAAW,MAAM,iBAAO,cAAc,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;AAAA,EAClE;AACA,SAAO;AACT;", - "names": [] -} diff --git a/backend/dist/lib/db.js b/backend/dist/lib/db.js deleted file mode 100644 index f896300c..00000000 --- a/backend/dist/lib/db.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var db_exports = {}; -__export(db_exports, { - prisma: () => prisma -}); -module.exports = __toCommonJS(db_exports); -var import_client = require("@prisma/client"); -const prisma = new import_client.PrismaClient({ - log: ["error", "warn"], - errorFormat: "pretty" -}); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - prisma -}); -//# sourceMappingURL=db.js.map diff --git a/backend/dist/lib/db.js.map b/backend/dist/lib/db.js.map deleted file mode 100644 index 3d3514f0..00000000 --- a/backend/dist/lib/db.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/db.ts"], - "sourcesContent": ["import { PrismaClient } from \"@prisma/client\";\n\nexport const prisma = new PrismaClient({\n log: [\"error\", \"warn\"],\n errorFormat: \"pretty\",\n});\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA6B;AAEtB,MAAM,SAAS,IAAI,2BAAa;AAAA,EACrC,KAAK,CAAC,SAAS,MAAM;AAAA,EACrB,aAAa;AACf,CAAC;", - "names": [] -} diff --git a/backend/dist/lib/encryption.js b/backend/dist/lib/encryption.js deleted file mode 100644 index 204001fc..00000000 --- a/backend/dist/lib/encryption.js +++ /dev/null @@ -1,50 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var encryption_exports = {}; -__export(encryption_exports, { - decrypt: () => decrypt, - encrypt: () => encrypt -}); -module.exports = __toCommonJS(encryption_exports); -var import_crypto = require("crypto"); -var import_env = require("./env"); -const ALGORITHM = "aes-256-gcm"; -const KEY = Buffer.from(import_env.env.ENCRYPTION_KEY, "hex"); -function encrypt(plaintext) { - const iv = (0, import_crypto.randomBytes)(12); - const cipher = (0, import_crypto.createCipheriv)(ALGORITHM, KEY, iv); - const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]); - const authTag = cipher.getAuthTag(); - return Buffer.concat([iv, authTag, encrypted]).toString("base64"); -} -function decrypt(ciphertext) { - const buf = Buffer.from(ciphertext, "base64"); - const iv = buf.slice(0, 12); - const authTag = buf.slice(12, 28); - const encrypted = buf.slice(28); - const decipher = (0, import_crypto.createDecipheriv)(ALGORITHM, KEY, iv); - decipher.setAuthTag(authTag); - return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8"); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - decrypt, - encrypt -}); -//# sourceMappingURL=encryption.js.map diff --git a/backend/dist/lib/encryption.js.map b/backend/dist/lib/encryption.js.map deleted file mode 100644 index cf82a7c1..00000000 --- a/backend/dist/lib/encryption.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/encryption.ts"], - "sourcesContent": ["import { createCipheriv, createDecipheriv, randomBytes } from \"crypto\";\nimport { env } from \"./env\";\n\nconst ALGORITHM = \"aes-256-gcm\";\nconst KEY = Buffer.from(env.ENCRYPTION_KEY, \"hex\");\n\nexport function encrypt(plaintext: string): string {\n const iv = randomBytes(12);\n const cipher = createCipheriv(ALGORITHM, KEY, iv);\n const encrypted = Buffer.concat([cipher.update(plaintext, \"utf8\"), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]).toString(\"base64\");\n}\n\nexport function decrypt(ciphertext: string): string {\n const buf = Buffer.from(ciphertext, \"base64\");\n const iv = buf.slice(0, 12);\n const authTag = buf.slice(12, 28);\n const encrypted = buf.slice(28);\n const decipher = createDecipheriv(ALGORITHM, KEY, iv);\n decipher.setAuthTag(authTag);\n return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString(\"utf8\");\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA8D;AAC9D,iBAAoB;AAEpB,MAAM,YAAY;AAClB,MAAM,MAAM,OAAO,KAAK,eAAI,gBAAgB,KAAK;AAE1C,SAAS,QAAQ,WAA2B;AACjD,QAAM,SAAK,2BAAY,EAAE;AACzB,QAAM,aAAS,8BAAe,WAAW,KAAK,EAAE;AAChD,QAAM,YAAY,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AAClF,QAAM,UAAU,OAAO,WAAW;AAClC,SAAO,OAAO,OAAO,CAAC,IAAI,SAAS,SAAS,CAAC,EAAE,SAAS,QAAQ;AAClE;AAEO,SAAS,QAAQ,YAA4B;AAClD,QAAM,MAAM,OAAO,KAAK,YAAY,QAAQ;AAC5C,QAAM,KAAK,IAAI,MAAM,GAAG,EAAE;AAC1B,QAAM,UAAU,IAAI,MAAM,IAAI,EAAE;AAChC,QAAM,YAAY,IAAI,MAAM,EAAE;AAC9B,QAAM,eAAW,gCAAiB,WAAW,KAAK,EAAE;AACpD,WAAS,WAAW,OAAO;AAC3B,SAAO,OAAO,OAAO,CAAC,SAAS,OAAO,SAAS,GAAG,SAAS,MAAM,CAAC,CAAC,EAAE,SAAS,MAAM;AACtF;", - "names": [] -} diff --git a/backend/dist/lib/env.js b/backend/dist/lib/env.js deleted file mode 100644 index 17e7eb1e..00000000 --- a/backend/dist/lib/env.js +++ /dev/null @@ -1,58 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var env_exports = {}; -__export(env_exports, { - env: () => env -}); -module.exports = __toCommonJS(env_exports); -var import_dotenv = __toESM(require("dotenv")); -var import_path = require("path"); -var import_zod = require("zod"); -import_dotenv.default.config({ path: (0, import_path.join)(__dirname, "../../.env") }); -const schema = import_zod.z.object({ - NODE_ENV: import_zod.z.enum(["development", "production", "test"]).default("development"), - DATABASE_URL: import_zod.z.string().min(1), - PORT: import_zod.z.coerce.number().int().positive().default(5e3), - SESSION_SECRET: import_zod.z.string().min(16), - PP_BASE_URL: import_zod.z.string().min(1), - ENCRYPTION_KEY: import_zod.z.string().length(64, "ENCRYPTION_KEY must be 64 hex chars (32 bytes AES-256)"), - LOG_LEVEL: import_zod.z.string().default("info") -}); -const result = schema.safeParse(process.env); -if (!result.success) { - const formatted = result.error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n"); - throw new Error(`Invalid environment variables: -${formatted}`); -} -const env = result.data; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - env -}); -//# sourceMappingURL=env.js.map diff --git a/backend/dist/lib/env.js.map b/backend/dist/lib/env.js.map deleted file mode 100644 index 337420fa..00000000 --- a/backend/dist/lib/env.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/env.ts"], - "sourcesContent": ["import dotenv from \"dotenv\";\nimport { join } from \"path\";\nimport { z } from \"zod\";\n\ndotenv.config({ path: join(__dirname, \"../../.env\") });\n\nconst schema = z.object({\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n DATABASE_URL: z.string().min(1),\n PORT: z.coerce.number().int().positive().default(5000),\n SESSION_SECRET: z.string().min(16),\n PP_BASE_URL: z.string().min(1),\n ENCRYPTION_KEY: z.string().length(64, \"ENCRYPTION_KEY must be 64 hex chars (32 bytes AES-256)\"),\n LOG_LEVEL: z.string().default(\"info\"),\n});\n\nconst result = schema.safeParse(process.env);\n\nif (!result.success) {\n const formatted = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid environment variables:\\n${formatted}`);\n}\n\nexport const env = result.data;\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AACnB,kBAAqB;AACrB,iBAAkB;AAElB,cAAAA,QAAO,OAAO,EAAE,UAAM,kBAAK,WAAW,YAAY,EAAE,CAAC;AAErD,MAAM,SAAS,aAAE,OAAO;AAAA,EACtB,UAAU,aAAE,KAAK,CAAC,eAAe,cAAc,MAAM,CAAC,EAAE,QAAQ,aAAa;AAAA,EAC7E,cAAc,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,MAAM,aAAE,OAAO,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAI;AAAA,EACrD,gBAAgB,aAAE,OAAO,EAAE,IAAI,EAAE;AAAA,EACjC,aAAa,aAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,gBAAgB,aAAE,OAAO,EAAE,OAAO,IAAI,wDAAwD;AAAA,EAC9F,WAAW,aAAE,OAAO,EAAE,QAAQ,MAAM;AACtC,CAAC;AAED,MAAM,SAAS,OAAO,UAAU,QAAQ,GAAG;AAE3C,IAAI,CAAC,OAAO,SAAS;AACnB,QAAM,YAAY,OAAO,MAAM,OAC5B,IAAI,CAAC,MAAM,KAAK,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAChD,KAAK,IAAI;AACZ,QAAM,IAAI,MAAM;AAAA,EAAmC,SAAS,EAAE;AAChE;AAEO,MAAM,MAAM,OAAO;", - "names": ["dotenv"] -} diff --git a/backend/dist/lib/errors.js b/backend/dist/lib/errors.js deleted file mode 100644 index a586d80c..00000000 --- a/backend/dist/lib/errors.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var errors_exports = {}; -__export(errors_exports, { - ERROR_MESSAGES: () => ERROR_MESSAGES -}); -module.exports = __toCommonJS(errors_exports); -const ERROR_MESSAGES = { - UNAUTHORIZED: { code: 401, message: "You are not authorized to access this resource." }, - FORBIDDEN: { code: 403, message: "You do not have permission to access this resource." }, - NOT_FOUND: { code: 404, message: "The requested resource was not found." }, - INTERNAL_SERVER_ERROR: { code: 500, message: "An unexpected server error has occurred." }, - BAD_REQUEST: { code: 400, message: "The request was invalid or malformed." }, - CONFLICT: { code: 409, message: "The request conflicts with the current state of the resource." }, - TOO_MANY_REQUESTS: { code: 429, message: "Too many requests. Please try again later." } -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - ERROR_MESSAGES -}); -//# sourceMappingURL=errors.js.map diff --git a/backend/dist/lib/errors.js.map b/backend/dist/lib/errors.js.map deleted file mode 100644 index 0ce1085e..00000000 --- a/backend/dist/lib/errors.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/errors.ts"], - "sourcesContent": ["export const ERROR_MESSAGES = {\n UNAUTHORIZED: { code: 401, message: \"You are not authorized to access this resource.\" },\n FORBIDDEN: { code: 403, message: \"You do not have permission to access this resource.\" },\n NOT_FOUND: { code: 404, message: \"The requested resource was not found.\" },\n INTERNAL_SERVER_ERROR: { code: 500, message: \"An unexpected server error has occurred.\" },\n BAD_REQUEST: { code: 400, message: \"The request was invalid or malformed.\" },\n CONFLICT: { code: 409, message: \"The request conflicts with the current state of the resource.\" },\n TOO_MANY_REQUESTS: { code: 429, message: \"Too many requests. Please try again later.\" },\n} as const;\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,iBAAiB;AAAA,EAC5B,cAAc,EAAE,MAAM,KAAK,SAAS,kDAAkD;AAAA,EACtF,WAAW,EAAE,MAAM,KAAK,SAAS,sDAAsD;AAAA,EACvF,WAAW,EAAE,MAAM,KAAK,SAAS,wCAAwC;AAAA,EACzE,uBAAuB,EAAE,MAAM,KAAK,SAAS,2CAA2C;AAAA,EACxF,aAAa,EAAE,MAAM,KAAK,SAAS,wCAAwC;AAAA,EAC3E,UAAU,EAAE,MAAM,KAAK,SAAS,gEAAgE;AAAA,EAChG,mBAAmB,EAAE,MAAM,KAAK,SAAS,6CAA6C;AACxF;", - "names": [] -} diff --git a/backend/dist/lib/logger.js b/backend/dist/lib/logger.js deleted file mode 100644 index 105abfa7..00000000 --- a/backend/dist/lib/logger.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var logger_exports = {}; -__export(logger_exports, { - createLogger: () => createLogger, - logger: () => logger -}); -module.exports = __toCommonJS(logger_exports); -var import_env = require("./env"); -var import_pino = __toESM(require("pino")); -const logger = (0, import_pino.default)({ - level: import_env.env.LOG_LEVEL, - transport: import_env.env.NODE_ENV !== "production" ? { target: "pino-pretty", options: { colorize: true } } : void 0 -}); -function createLogger(component) { - return logger.child({ component }); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - createLogger, - logger -}); -//# sourceMappingURL=logger.js.map diff --git a/backend/dist/lib/logger.js.map b/backend/dist/lib/logger.js.map deleted file mode 100644 index 8221eee6..00000000 --- a/backend/dist/lib/logger.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/logger.ts"], - "sourcesContent": ["import { env } from \"./env\";\nimport pino from \"pino\";\n\nexport const logger = pino({\n level: env.LOG_LEVEL,\n transport:\n env.NODE_ENV !== \"production\"\n ? { target: \"pino-pretty\", options: { colorize: true } }\n : undefined,\n});\n\nexport function createLogger(component: string) {\n return logger.child({ component });\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,kBAAiB;AAEV,MAAM,aAAS,YAAAA,SAAK;AAAA,EACzB,OAAO,eAAI;AAAA,EACX,WACE,eAAI,aAAa,eACb,EAAE,QAAQ,eAAe,SAAS,EAAE,UAAU,KAAK,EAAE,IACrD;AACR,CAAC;AAEM,SAAS,aAAa,WAAmB;AAC9C,SAAO,OAAO,MAAM,EAAE,UAAU,CAAC;AACnC;", - "names": ["pino"] -} diff --git a/backend/dist/lib/middlewares/auth.js b/backend/dist/lib/middlewares/auth.js deleted file mode 100644 index 12f1869c..00000000 --- a/backend/dist/lib/middlewares/auth.js +++ /dev/null @@ -1,88 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var auth_exports = {}; -__export(auth_exports, { - COOKIE_NAME_EXPORT: () => COOKIE_NAME_EXPORT, - authEnforcementMiddleware: () => authEnforcementMiddleware, - authResolutionMiddleware: () => authResolutionMiddleware -}); -module.exports = __toCommonJS(auth_exports); -var import_rjweb_server = require("rjweb-server"); -var import_db = require("../db"); -var import_logger = require("../logger"); -var import_errors = require("../errors"); -const log = (0, import_logger.createLogger)("AUTH"); -const COOKIE_NAME = "pp_session"; -const authResolutionMiddleware = new import_rjweb_server.Middleware( - "Auth Resolution Middleware", - "1.0.0" -).load(() => { - log.info("Auth resolution middleware loaded"); -}).httpRequest(async (_config, _server, context, ctr) => { - const cookieToken = ctr.cookies.get(COOKIE_NAME); - const tokenProvided = Boolean(cookieToken); - const data = context.data(authResolutionMiddleware); - if (!cookieToken) { - data.auth = { success: false, message: "No session", tokenProvided: false }; - return; - } - const session = await import_db.prisma.session.findFirst({ - where: { hash: cookieToken }, - include: { user: true } - }); - if (!session) { - data.auth = { success: false, message: "Invalid session", tokenProvided }; - return; - } - data.auth = { success: true, user: session.user, sessionId: session.id }; -}).httpRequestContext( - (_config, Original) => class extends Original { - getAuth() { - const data = this.context.data(authResolutionMiddleware); - if (!data.auth) { - return { success: false, message: "Auth not resolved", tokenProvided: false }; - } - return data.auth; - } - } -).export(); -const authEnforcementMiddleware = new import_rjweb_server.Middleware( - "Auth Enforcement Middleware", - "1.0.0" -).httpRequest(async (_config, _server, context, ctr, end) => { - const data = context.data(authResolutionMiddleware); - const auth = data.auth; - if (!auth || auth.success || !auth.tokenProvided) { - return; - } - return end( - ctr.status(import_errors.ERROR_MESSAGES.UNAUTHORIZED.code).print({ - status: "FAILED", - message: auth.message - }) - ); -}).export(); -const COOKIE_NAME_EXPORT = COOKIE_NAME; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - COOKIE_NAME_EXPORT, - authEnforcementMiddleware, - authResolutionMiddleware -}); -//# sourceMappingURL=auth.js.map diff --git a/backend/dist/lib/middlewares/auth.js.map b/backend/dist/lib/middlewares/auth.js.map deleted file mode 100644 index 35f61100..00000000 --- a/backend/dist/lib/middlewares/auth.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/lib/middlewares/auth.ts"], - "sourcesContent": ["import { Middleware } from \"rjweb-server\";\nimport { type User } from \"@prisma/client\";\nimport { prisma } from \"../db\";\nimport { createLogger } from \"../logger\";\nimport { ERROR_MESSAGES } from \"../errors\";\n\nconst log = createLogger(\"AUTH\");\n\nconst COOKIE_NAME = \"pp_session\";\n\nexport type AuthState =\n | { success: true; user: User; sessionId: number }\n | { success: false; message: string; tokenProvided: boolean };\n\ntype AuthContext = {\n auth?: AuthState;\n};\n\nexport const authResolutionMiddleware = new Middleware<{}, AuthContext>(\n \"Auth Resolution Middleware\",\n \"1.0.0\",\n)\n .load(() => {\n log.info(\"Auth resolution middleware loaded\");\n })\n .httpRequest(async (_config, _server, context, ctr) => {\n const cookieToken = ctr.cookies.get(COOKIE_NAME);\n const tokenProvided = Boolean(cookieToken);\n const data = context.data(authResolutionMiddleware);\n\n if (!cookieToken) {\n data.auth = { success: false, message: \"No session\", tokenProvided: false };\n return;\n }\n\n const session = await prisma.session.findFirst({\n where: { hash: cookieToken },\n include: { user: true },\n });\n\n if (!session) {\n data.auth = { success: false, message: \"Invalid session\", tokenProvided };\n return;\n }\n\n data.auth = { success: true, user: session.user, sessionId: session.id };\n })\n .httpRequestContext(\n (_config, Original) =>\n class extends Original {\n getAuth(): AuthState {\n const data = this.context.data(authResolutionMiddleware);\n if (!data.auth) {\n return { success: false, message: \"Auth not resolved\", tokenProvided: false };\n }\n return data.auth;\n }\n },\n )\n .export();\n\nexport const authEnforcementMiddleware = new Middleware<{}, {}>(\n \"Auth Enforcement Middleware\",\n \"1.0.0\",\n)\n .httpRequest(async (_config, _server, context, ctr, end) => {\n const data = context.data(authResolutionMiddleware) as AuthContext;\n const auth = data.auth;\n\n if (!auth || auth.success || !auth.tokenProvided) {\n return;\n }\n\n return end(\n ctr.status(ERROR_MESSAGES.UNAUTHORIZED.code).print({\n status: \"FAILED\",\n message: auth.message,\n }),\n );\n })\n .export();\n\nexport const COOKIE_NAME_EXPORT = COOKIE_NAME;\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA2B;AAE3B,gBAAuB;AACvB,oBAA6B;AAC7B,oBAA+B;AAE/B,MAAM,UAAM,4BAAa,MAAM;AAE/B,MAAM,cAAc;AAUb,MAAM,2BAA2B,IAAI;AAAA,EAC1C;AAAA,EACA;AACF,EACG,KAAK,MAAM;AACV,MAAI,KAAK,mCAAmC;AAC9C,CAAC,EACA,YAAY,OAAO,SAAS,SAAS,SAAS,QAAQ;AACrD,QAAM,cAAc,IAAI,QAAQ,IAAI,WAAW;AAC/C,QAAM,gBAAgB,QAAQ,WAAW;AACzC,QAAM,OAAO,QAAQ,KAAK,wBAAwB;AAElD,MAAI,CAAC,aAAa;AAChB,SAAK,OAAO,EAAE,SAAS,OAAO,SAAS,cAAc,eAAe,MAAM;AAC1E;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,iBAAO,QAAQ,UAAU;AAAA,IAC7C,OAAO,EAAE,MAAM,YAAY;AAAA,IAC3B,SAAS,EAAE,MAAM,KAAK;AAAA,EACxB,CAAC;AAED,MAAI,CAAC,SAAS;AACZ,SAAK,OAAO,EAAE,SAAS,OAAO,SAAS,mBAAmB,cAAc;AACxE;AAAA,EACF;AAEA,OAAK,OAAO,EAAE,SAAS,MAAM,MAAM,QAAQ,MAAM,WAAW,QAAQ,GAAG;AACzE,CAAC,EACA;AAAA,EACC,CAAC,SAAS,aACR,cAAc,SAAS;AAAA,IACrB,UAAqB;AACnB,YAAM,OAAO,KAAK,QAAQ,KAAK,wBAAwB;AACvD,UAAI,CAAC,KAAK,MAAM;AACd,eAAO,EAAE,SAAS,OAAO,SAAS,qBAAqB,eAAe,MAAM;AAAA,MAC9E;AACA,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACJ,EACC,OAAO;AAEH,MAAM,4BAA4B,IAAI;AAAA,EAC3C;AAAA,EACA;AACF,EACG,YAAY,OAAO,SAAS,SAAS,SAAS,KAAK,QAAQ;AAC1D,QAAM,OAAO,QAAQ,KAAK,wBAAwB;AAClD,QAAM,OAAO,KAAK;AAElB,MAAI,CAAC,QAAQ,KAAK,WAAW,CAAC,KAAK,eAAe;AAChD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,OAAO,6BAAe,aAAa,IAAI,EAAE,MAAM;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AACF,CAAC,EACA,OAAO;AAEH,MAAM,qBAAqB;", - "names": [] -} diff --git a/backend/dist/lib/middlewares/cors.js b/backend/dist/lib/middlewares/cors.js deleted file mode 100644 index e3091703..00000000 --- a/backend/dist/lib/middlewares/cors.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var cors_exports = {}; -__export(cors_exports, { - corsMiddleware: () => corsMiddleware -}); -module.exports = __toCommonJS(cors_exports); -var import_rjweb_server = require("rjweb-server"); -var import_env = require("../env"); -const ALLOWED_ORIGINS = /* @__PURE__ */ new Set([import_env.env.PP_BASE_URL]); -const corsMiddleware = new import_rjweb_server.Middleware("CORS Middleware", "1.0.0").httpRequest(async (_config, _server, _context, ctr) => { - const origin = ctr.headers.get("origin") || ""; - if (ALLOWED_ORIGINS.has(origin) || import_env.env.NODE_ENV === "development") { - ctr.headers.set("Access-Control-Allow-Origin", origin || "*"); - ctr.headers.set("Access-Control-Allow-Credentials", "true"); - ctr.headers.set("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS"); - ctr.headers.set("Access-Control-Allow-Headers", "Content-Type,Authorization,X-Requested-With"); - } -}).export(); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - corsMiddleware -}); -//# sourceMappingURL=cors.js.map diff --git a/backend/dist/lib/middlewares/cors.js.map b/backend/dist/lib/middlewares/cors.js.map deleted file mode 100644 index a817b741..00000000 --- a/backend/dist/lib/middlewares/cors.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/lib/middlewares/cors.ts"], - "sourcesContent": ["import { Middleware } from \"rjweb-server\";\nimport { env } from \"../env\";\n\nconst ALLOWED_ORIGINS = new Set([env.PP_BASE_URL]);\n\nexport const corsMiddleware = new Middleware<{}, {}>(\"CORS Middleware\", \"1.0.0\")\n .httpRequest(async (_config, _server, _context, ctr) => {\n const origin = ctr.headers.get(\"origin\") || \"\";\n if (ALLOWED_ORIGINS.has(origin) || env.NODE_ENV === \"development\") {\n ctr.headers.set(\"Access-Control-Allow-Origin\", origin || \"*\");\n ctr.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n ctr.headers.set(\"Access-Control-Allow-Methods\", \"GET,POST,PUT,PATCH,DELETE,OPTIONS\");\n ctr.headers.set(\"Access-Control-Allow-Headers\", \"Content-Type,Authorization,X-Requested-With\");\n }\n })\n .export();\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA2B;AAC3B,iBAAoB;AAEpB,MAAM,kBAAkB,oBAAI,IAAI,CAAC,eAAI,WAAW,CAAC;AAE1C,MAAM,iBAAiB,IAAI,+BAAmB,mBAAmB,OAAO,EAC5E,YAAY,OAAO,SAAS,SAAS,UAAU,QAAQ;AACtD,QAAM,SAAS,IAAI,QAAQ,IAAI,QAAQ,KAAK;AAC5C,MAAI,gBAAgB,IAAI,MAAM,KAAK,eAAI,aAAa,eAAe;AACjE,QAAI,QAAQ,IAAI,+BAA+B,UAAU,GAAG;AAC5D,QAAI,QAAQ,IAAI,oCAAoC,MAAM;AAC1D,QAAI,QAAQ,IAAI,gCAAgC,mCAAmC;AACnF,QAAI,QAAQ,IAAI,gCAAgC,6CAA6C;AAAA,EAC/F;AACF,CAAC,EACA,OAAO;", - "names": [] -} diff --git a/backend/dist/lib/middlewares/main.js b/backend/dist/lib/middlewares/main.js deleted file mode 100644 index 830aa54c..00000000 --- a/backend/dist/lib/middlewares/main.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var main_exports = {}; -__export(main_exports, { - mainMiddleware: () => mainMiddleware -}); -module.exports = __toCommonJS(main_exports); -var import_rjweb_server = require("rjweb-server"); -var import_logger = require("../logger"); -const log = (0, import_logger.createLogger)("HTTP"); -const mainMiddleware = new import_rjweb_server.Middleware("Main Middleware", "1.0.0").load(() => { - log.info("Main middleware loaded"); -}).httpRequest(async (_config, _server, _context, ctr) => { - if (ctr.url.method === "OPTIONS") { - ctr.status(204).print(""); - } -}).export(); -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - mainMiddleware -}); -//# sourceMappingURL=main.js.map diff --git a/backend/dist/lib/middlewares/main.js.map b/backend/dist/lib/middlewares/main.js.map deleted file mode 100644 index 3ebecafa..00000000 --- a/backend/dist/lib/middlewares/main.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/lib/middlewares/main.ts"], - "sourcesContent": ["import { Middleware } from \"rjweb-server\";\nimport { createLogger } from \"../logger\";\n\nconst log = createLogger(\"HTTP\");\n\nexport const mainMiddleware = new Middleware<{}, {}>(\"Main Middleware\", \"1.0.0\")\n .load(() => {\n log.info(\"Main middleware loaded\");\n })\n .httpRequest(async (_config, _server, _context, ctr) => {\n if (ctr.url.method === \"OPTIONS\") {\n ctr.status(204).print(\"\");\n }\n })\n .export();\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAA2B;AAC3B,oBAA6B;AAE7B,MAAM,UAAM,4BAAa,MAAM;AAExB,MAAM,iBAAiB,IAAI,+BAAmB,mBAAmB,OAAO,EAC5E,KAAK,MAAM;AACV,MAAI,KAAK,wBAAwB;AACnC,CAAC,EACA,YAAY,OAAO,SAAS,SAAS,UAAU,QAAQ;AACtD,MAAI,IAAI,IAAI,WAAW,WAAW;AAChC,QAAI,OAAO,GAAG,EAAE,MAAM,EAAE;AAAA,EAC1B;AACF,CAAC,EACA,OAAO;", - "names": [] -} diff --git a/backend/dist/lib/response.js b/backend/dist/lib/response.js deleted file mode 100644 index 4dd6c7c8..00000000 --- a/backend/dist/lib/response.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var response_exports = {}; -__export(response_exports, { - endResponse: () => endResponse, - makeResponse: () => makeResponse -}); -module.exports = __toCommonJS(response_exports); -var import_errors = require("./errors"); -function resolve(content) { - const code = "code" in content ? content.code : content.status; - const message = code >= 500 ? import_errors.ERROR_MESSAGES.INTERNAL_SERVER_ERROR.message : content.message; - return { code, message }; -} -function buildBody(code, message, data) { - if (code >= 400) { - return { status: "FAILED", message }; - } - return { - status: "OK", - ...message !== void 0 ? { message } : {}, - ...data !== void 0 ? { data } : {} - }; -} -async function makeResponse({ - ctr, - content -}) { - const { code, message } = resolve(content); - const data = "data" in content ? content.data : void 0; - return ctr.status(code).print(buildBody(code, message, data)); -} -async function endResponse({ - ctr, - end, - content -}) { - const { code, message } = resolve(content); - const data = "data" in content ? content.data : void 0; - ctr.status(code).print(buildBody(code, message, data)); - end(); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - endResponse, - makeResponse -}); -//# sourceMappingURL=response.js.map diff --git a/backend/dist/lib/response.js.map b/backend/dist/lib/response.js.map deleted file mode 100644 index 5aa2aa99..00000000 --- a/backend/dist/lib/response.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/lib/response.ts"], - "sourcesContent": ["import { ERROR_MESSAGES } from \"./errors\";\n\ntype ResponseContent =\n | { code: number; message?: string; data?: unknown }\n | { status: number; message?: string; data?: unknown };\n\nfunction resolve(content: ResponseContent) {\n const code = \"code\" in content ? content.code : content.status;\n const message = code >= 500 ? ERROR_MESSAGES.INTERNAL_SERVER_ERROR.message : content.message;\n return { code, message };\n}\n\nfunction buildBody(code: number, message: string | undefined, data: unknown) {\n if (code >= 400) {\n return { status: \"FAILED\", message };\n }\n return {\n status: \"OK\",\n ...(message !== undefined ? { message } : {}),\n ...(data !== undefined ? { data } : {}),\n };\n}\n\nexport async function makeResponse({\n ctr,\n content,\n}: {\n ctr: any;\n content: ResponseContent;\n}) {\n const { code, message } = resolve(content);\n const data = \"data\" in content ? content.data : undefined;\n return ctr.status(code).print(buildBody(code, message, data));\n}\n\nexport async function endResponse({\n ctr,\n end,\n content,\n}: {\n ctr: any;\n end: () => void;\n content: ResponseContent;\n}) {\n const { code, message } = resolve(content);\n const data = \"data\" in content ? content.data : undefined;\n ctr.status(code).print(buildBody(code, message, data));\n end();\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAM/B,SAAS,QAAQ,SAA0B;AACzC,QAAM,OAAO,UAAU,UAAU,QAAQ,OAAO,QAAQ;AACxD,QAAM,UAAU,QAAQ,MAAM,6BAAe,sBAAsB,UAAU,QAAQ;AACrF,SAAO,EAAE,MAAM,QAAQ;AACzB;AAEA,SAAS,UAAU,MAAc,SAA6B,MAAe;AAC3E,MAAI,QAAQ,KAAK;AACf,WAAO,EAAE,QAAQ,UAAU,QAAQ;AAAA,EACrC;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3C,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,EACvC;AACF;AAEA,eAAsB,aAAa;AAAA,EACjC;AAAA,EACA;AACF,GAGG;AACD,QAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ,OAAO;AACzC,QAAM,OAAO,UAAU,UAAU,QAAQ,OAAO;AAChD,SAAO,IAAI,OAAO,IAAI,EAAE,MAAM,UAAU,MAAM,SAAS,IAAI,CAAC;AAC9D;AAEA,eAAsB,YAAY;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ,OAAO;AACzC,QAAM,OAAO,UAAU,UAAU,QAAQ,OAAO;AAChD,MAAI,OAAO,IAAI,EAAE,MAAM,UAAU,MAAM,SAAS,IAAI,CAAC;AACrD,MAAI;AACN;", - "names": [] -} diff --git a/backend/dist/routes/api/admin.js b/backend/dist/routes/api/admin.js deleted file mode 100644 index 292820e1..00000000 --- a/backend/dist/routes/api/admin.js +++ /dev/null @@ -1,192 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var admin_exports = {}; -__export(admin_exports, { - adminListPreviews: () => adminListPreviews, - adminStopPreview: () => adminStopPreview, - createUser: () => createUser, - deleteUser: () => deleteUser, - getSettings: () => getSettings, - listUsers: () => listUsers, - updateSettings: () => updateSettings, - updateUser: () => updateUser -}); -module.exports = __toCommonJS(admin_exports); -var import_bcryptjs = __toESM(require("bcryptjs")); -var import_db = require("../../lib/db"); -var import_response = require("../../lib/response"); -var import_errors = require("../../lib/errors"); -var import_adminSettings = require("../../lib/adminSettings"); -function requireAdmin(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) return null; - if (!auth.user.isAdmin) return null; - return auth.user; -} -async function listUsers(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const users = await import_db.prisma.user.findMany({ - select: { id: true, username: true, isAdmin: true, isFounder: true, createdAt: true, giteaInstanceUrl: true }, - orderBy: { createdAt: "asc" } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: users } }); -} -async function createUser(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const body = await ctr.body(); - const { username, password } = body || {}; - if (!username || !password) return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Username and password required" } }); - const existing = await import_db.prisma.user.findUnique({ where: { username } }); - if (existing) return (0, import_response.makeResponse)({ ctr, content: { code: 409, message: "Username already taken" } }); - const userCount = await import_db.prisma.user.count(); - const isFirst = userCount === 0; - const hash = await import_bcryptjs.default.hash(password, 12); - const user = await import_db.prisma.user.create({ - data: { username, passwordHash: hash, isAdmin: isFirst, isFounder: isFirst }, - select: { id: true, username: true, isAdmin: true, isFounder: true } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 201, data: user } }); -} -async function updateUser(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const id = parseInt(ctr.params.get("id") || "0", 10); - const target = await import_db.prisma.user.findUnique({ where: { id } }); - if (!target) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); - const body = await ctr.body(); - const { username, password, isAdmin } = body || {}; - const data = {}; - if (username) { - const existing = await import_db.prisma.user.findFirst({ where: { username, id: { not: id } } }); - if (existing) return (0, import_response.makeResponse)({ ctr, content: { code: 409, message: "Username taken" } }); - data.username = username; - } - if (password) data.passwordHash = await import_bcryptjs.default.hash(password, 12); - if (isAdmin !== void 0 && !target.isFounder) data.isAdmin = Boolean(isAdmin); - await import_db.prisma.user.update({ where: { id }, data }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "User updated" } }); -} -async function deleteUser(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const id = parseInt(ctr.params.get("id") || "0", 10); - const target = await import_db.prisma.user.findUnique({ where: { id } }); - if (!target) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); - if (target.isFounder) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: "Cannot delete founder" } }); - if (id === admin.id) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: "Cannot delete yourself" } }); - await import_db.prisma.user.delete({ where: { id } }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "User deleted" } }); -} -async function getSettings(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const settings = await (0, import_adminSettings.getAdminSettings)(); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: settings } }); -} -async function updateSettings(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const body = await ctr.body(); - const { - defaultInstanceType, - maxConcurrentInstancesPerUser, - logSizeLimitBytes, - previewRetentionDays, - webhookRateLimitPerMinute, - contactEmail - } = body || {}; - const data = {}; - if (defaultInstanceType) data.defaultInstanceType = defaultInstanceType; - if (maxConcurrentInstancesPerUser) data.maxConcurrentInstancesPerUser = Number(maxConcurrentInstancesPerUser); - if (logSizeLimitBytes) data.logSizeLimitBytes = Number(logSizeLimitBytes); - if (previewRetentionDays) data.previewRetentionDays = Number(previewRetentionDays); - if (webhookRateLimitPerMinute) data.webhookRateLimitPerMinute = Number(webhookRateLimitPerMinute); - if (contactEmail !== void 0) data.contactEmail = contactEmail; - await import_db.prisma.adminSettings.upsert({ - where: { id: 1 }, - update: data, - create: { id: 1, ...data } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Settings updated" } }); -} -async function adminListPreviews(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const previews = await import_db.prisma.preview.findMany({ - include: { - repoConfig: { include: { user: { select: { id: true, username: true } } } } - }, - orderBy: { updatedAt: "desc" }, - take: 200 - }); - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - data: previews.map((p) => ({ - id: p.id, - prNumber: p.prNumber, - prTitle: p.prTitle, - status: p.status, - instanceIp: p.instanceIp, - port: p.port, - createdAt: p.createdAt, - updatedAt: p.updatedAt, - repoOwner: p.repoConfig.repoOwner, - repoName: p.repoConfig.repoName, - user: p.repoConfig.user - })) - } - }); -} -async function adminStopPreview(ctr) { - const admin = requireAdmin(ctr); - if (!admin) return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: import_errors.ERROR_MESSAGES.FORBIDDEN.message } }); - const id = parseInt(ctr.params.get("id") || "0", 10); - const preview = await import_db.prisma.preview.findUnique({ where: { id } }); - if (!preview) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); - await import_db.prisma.job.create({ - data: { previewId: id, type: "STOP", status: "PENDING", payload: { reason: "Admin stop" } } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Stop job enqueued" } }); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - adminListPreviews, - adminStopPreview, - createUser, - deleteUser, - getSettings, - listUsers, - updateSettings, - updateUser -}); -//# sourceMappingURL=admin.js.map diff --git a/backend/dist/routes/api/admin.js.map b/backend/dist/routes/api/admin.js.map deleted file mode 100644 index f7a5e769..00000000 --- a/backend/dist/routes/api/admin.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/routes/api/admin.ts"], - "sourcesContent": ["import bcrypt from \"bcryptjs\";\r\nimport { prisma } from \"../../lib/db\";\r\nimport { makeResponse } from \"../../lib/response\";\r\nimport { ERROR_MESSAGES } from \"../../lib/errors\";\r\nimport { getAdminSettings } from \"../../lib/adminSettings\";\r\n\r\nfunction requireAdmin(ctr: any) {\r\n const auth = ctr.getAuth?.();\r\n if (!auth?.success) return null;\r\n if (!auth.user.isAdmin) return null;\r\n return auth.user;\r\n}\r\n\r\nexport async function listUsers(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const users = await prisma.user.findMany({\r\n select: { id: true, username: true, isAdmin: true, isFounder: true, createdAt: true, giteaInstanceUrl: true },\r\n orderBy: { createdAt: \"asc\" },\r\n });\r\n\r\n return makeResponse({ ctr, content: { code: 200, data: users } });\r\n}\r\n\r\nexport async function createUser(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const body = await ctr.body();\r\n const { username, password } = body || {};\r\n if (!username || !password) return makeResponse({ ctr, content: { code: 400, message: \"Username and password required\" } });\r\n\r\n const existing = await prisma.user.findUnique({ where: { username } });\r\n if (existing) return makeResponse({ ctr, content: { code: 409, message: \"Username already taken\" } });\r\n\r\n const userCount = await prisma.user.count();\r\n const isFirst = userCount === 0;\r\n const hash = await bcrypt.hash(password, 12);\r\n\r\n const user = await prisma.user.create({\r\n data: { username, passwordHash: hash, isAdmin: isFirst, isFounder: isFirst },\r\n select: { id: true, username: true, isAdmin: true, isFounder: true },\r\n });\r\n\r\n return makeResponse({ ctr, content: { code: 201, data: user } });\r\n}\r\n\r\nexport async function updateUser(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\r\n const target = await prisma.user.findUnique({ where: { id } });\r\n if (!target) return makeResponse({ ctr, content: { code: 404, message: ERROR_MESSAGES.NOT_FOUND.message } });\r\n\r\n const body = await ctr.body();\r\n const { username, password, isAdmin } = body || {};\r\n const data: any = {};\r\n\r\n if (username) {\r\n const existing = await prisma.user.findFirst({ where: { username, id: { not: id } } });\r\n if (existing) return makeResponse({ ctr, content: { code: 409, message: \"Username taken\" } });\r\n data.username = username;\r\n }\r\n if (password) data.passwordHash = await bcrypt.hash(password, 12);\r\n if (isAdmin !== undefined && !target.isFounder) data.isAdmin = Boolean(isAdmin);\r\n\r\n await prisma.user.update({ where: { id }, data });\r\n return makeResponse({ ctr, content: { code: 200, message: \"User updated\" } });\r\n}\r\n\r\nexport async function deleteUser(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\r\n const target = await prisma.user.findUnique({ where: { id } });\r\n if (!target) return makeResponse({ ctr, content: { code: 404, message: ERROR_MESSAGES.NOT_FOUND.message } });\r\n if (target.isFounder) return makeResponse({ ctr, content: { code: 403, message: \"Cannot delete founder\" } });\r\n if (id === admin.id) return makeResponse({ ctr, content: { code: 403, message: \"Cannot delete yourself\" } });\r\n\r\n await prisma.user.delete({ where: { id } });\r\n return makeResponse({ ctr, content: { code: 200, message: \"User deleted\" } });\r\n}\r\n\r\nexport async function getSettings(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const settings = await getAdminSettings();\r\n return makeResponse({ ctr, content: { code: 200, data: settings } });\r\n}\r\n\r\nexport async function updateSettings(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const body = await ctr.body();\r\n const {\r\n defaultInstanceType,\r\n maxConcurrentInstancesPerUser,\r\n logSizeLimitBytes,\r\n previewRetentionDays,\r\n webhookRateLimitPerMinute,\r\n contactEmail,\r\n } = body || {};\r\n\r\n const data: any = {};\r\n if (defaultInstanceType) data.defaultInstanceType = defaultInstanceType;\r\n if (maxConcurrentInstancesPerUser) data.maxConcurrentInstancesPerUser = Number(maxConcurrentInstancesPerUser);\r\n if (logSizeLimitBytes) data.logSizeLimitBytes = Number(logSizeLimitBytes);\r\n if (previewRetentionDays) data.previewRetentionDays = Number(previewRetentionDays);\r\n if (webhookRateLimitPerMinute) data.webhookRateLimitPerMinute = Number(webhookRateLimitPerMinute);\r\n if (contactEmail !== undefined) data.contactEmail = contactEmail;\r\n\r\n await prisma.adminSettings.upsert({\r\n where: { id: 1 },\r\n update: data,\r\n create: { id: 1, ...data },\r\n });\r\n\r\n return makeResponse({ ctr, content: { code: 200, message: \"Settings updated\" } });\r\n}\r\n\r\nexport async function adminListPreviews(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const previews = await prisma.preview.findMany({\r\n include: {\r\n repoConfig: { include: { user: { select: { id: true, username: true } } } },\r\n },\r\n orderBy: { updatedAt: \"desc\" },\r\n take: 200,\r\n });\r\n\r\n return makeResponse({\r\n ctr, content: {\r\n code: 200, data: previews.map(p => ({\r\n id: p.id,\r\n prNumber: p.prNumber,\r\n prTitle: p.prTitle,\r\n status: p.status,\r\n instanceIp: p.instanceIp,\r\n port: p.port,\r\n createdAt: p.createdAt,\r\n updatedAt: p.updatedAt,\r\n repoOwner: p.repoConfig.repoOwner,\r\n repoName: p.repoConfig.repoName,\r\n user: (p.repoConfig as any).user,\r\n }))\r\n }\r\n });\r\n}\r\n\r\nexport async function adminStopPreview(ctr: any) {\r\n const admin = requireAdmin(ctr);\r\n if (!admin) return makeResponse({ ctr, content: { code: 403, message: ERROR_MESSAGES.FORBIDDEN.message } });\r\n\r\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\r\n const preview = await prisma.preview.findUnique({ where: { id } });\r\n if (!preview) return makeResponse({ ctr, content: { code: 404, message: ERROR_MESSAGES.NOT_FOUND.message } });\r\n\r\n await prisma.job.create({\r\n data: { previewId: id, type: \"STOP\", status: \"PENDING\", payload: { reason: \"Admin stop\" } },\r\n });\r\n\r\n return makeResponse({ ctr, content: { code: 200, message: \"Stop job enqueued\" } });\r\n}\r\n"], - "mappings": "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", - "names": ["bcrypt"] -} diff --git a/backend/dist/routes/api/previews.js b/backend/dist/routes/api/previews.js deleted file mode 100644 index a00921ae..00000000 --- a/backend/dist/routes/api/previews.js +++ /dev/null @@ -1,153 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var previews_exports = {}; -__export(previews_exports, { - getPreview: () => getPreview, - listPreviews: () => listPreviews, - previewLogsWs: () => previewLogsWs, - stopPreviewRoute: () => stopPreviewRoute -}); -module.exports = __toCommonJS(previews_exports); -var import_db = require("../../lib/db"); -var import_response = require("../../lib/response"); -var import_errors = require("../../lib/errors"); -var import_deploy = require("../../services/deploy"); -function requireAuth(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) return null; - return auth.user; -} -async function listPreviews(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const previews = await import_db.prisma.preview.findMany({ - where: { repoConfig: { userId: user.id } }, - include: { repoConfig: { select: { repoOwner: true, repoName: true } } }, - orderBy: { updatedAt: "desc" } - }); - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - data: previews.map((p) => ({ - id: p.id, - prNumber: p.prNumber, - prTitle: p.prTitle, - commitSha: p.commitSha, - status: p.status, - instanceIp: p.instanceIp, - port: p.port, - createdAt: p.createdAt, - updatedAt: p.updatedAt, - lastActivityAt: p.lastActivityAt, - repoOwner: p.repoConfig.repoOwner, - repoName: p.repoConfig.repoName - })) - } - }); -} -async function getPreview(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const id = parseInt(ctr.params.get("id") || "0", 10); - const preview = await import_db.prisma.preview.findFirst({ - where: { id, repoConfig: { userId: user.id } }, - include: { - repoConfig: { select: { repoOwner: true, repoName: true } }, - jobs: { orderBy: { createdAt: "desc" }, take: 10 } - } - }); - if (!preview) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - data: { - id: preview.id, - prNumber: preview.prNumber, - prTitle: preview.prTitle, - commitSha: preview.commitSha, - status: preview.status, - instanceIp: preview.instanceIp, - port: preview.port, - logs: preview.logs, - createdAt: preview.createdAt, - updatedAt: preview.updatedAt, - stoppedAt: preview.stoppedAt, - lastActivityAt: preview.lastActivityAt, - repoOwner: preview.repoConfig.repoOwner, - repoName: preview.repoConfig.repoName, - jobs: preview.jobs.map((j) => ({ - id: j.id, - type: j.type, - status: j.status, - createdAt: j.createdAt, - startedAt: j.startedAt, - finishedAt: j.finishedAt, - error: j.error - })) - } - } - }); -} -async function stopPreviewRoute(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const id = parseInt(ctr.params.get("id") || "0", 10); - const preview = await import_db.prisma.preview.findFirst({ - where: { id, repoConfig: { userId: user.id } } - }); - if (!preview) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: import_errors.ERROR_MESSAGES.NOT_FOUND.message } }); - if (preview.status === "STOPPED") return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Already stopped" } }); - await import_db.prisma.job.create({ - data: { previewId: id, type: "STOP", status: "PENDING", payload: { reason: "Manual stop via UI" } } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Stop job enqueued" } }); -} -async function previewLogsWs(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) { - ctr.close(1008, "Unauthorized"); - return; - } - const id = parseInt(ctr.params.get("id") || "0", 10); - const preview = await import_db.prisma.preview.findFirst({ - where: { id, repoConfig: { userId: auth.user.id } } - }); - if (!preview) { - ctr.close(1008, "Not found"); - return; - } - await ctr.print(JSON.stringify({ type: "init", logs: preview.logs })); - const unsub = (0, import_deploy.subscribeToLogs)(id, (text) => { - try { - ctr.print(JSON.stringify({ type: "append", text })); - } catch { - } - }); - ctr.$abort(unsub); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - getPreview, - listPreviews, - previewLogsWs, - stopPreviewRoute -}); -//# sourceMappingURL=previews.js.map diff --git a/backend/dist/routes/api/previews.js.map b/backend/dist/routes/api/previews.js.map deleted file mode 100644 index 4b936544..00000000 --- a/backend/dist/routes/api/previews.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/routes/api/previews.ts"], - "sourcesContent": ["import { prisma } from \"../../lib/db\";\nimport { makeResponse } from \"../../lib/response\";\nimport { ERROR_MESSAGES } from \"../../lib/errors\";\nimport { subscribeToLogs } from \"../../services/deploy\";\n\nfunction requireAuth(ctr: any) {\n const auth = ctr.getAuth?.();\n if (!auth?.success) return null;\n return auth.user;\n}\n\nexport async function listPreviews(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const previews = await prisma.preview.findMany({\n where: { repoConfig: { userId: user.id } },\n include: { repoConfig: { select: { repoOwner: true, repoName: true } } },\n orderBy: { updatedAt: \"desc\" },\n });\n\n return makeResponse({\n ctr, content: {\n code: 200, data: previews.map(p => ({\n id: p.id,\n prNumber: p.prNumber,\n prTitle: p.prTitle,\n commitSha: p.commitSha,\n status: p.status,\n instanceIp: p.instanceIp,\n port: p.port,\n createdAt: p.createdAt,\n updatedAt: p.updatedAt,\n lastActivityAt: p.lastActivityAt,\n repoOwner: p.repoConfig.repoOwner,\n repoName: p.repoConfig.repoName,\n }))\n }\n });\n}\n\nexport async function getPreview(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\n const preview = await prisma.preview.findFirst({\n where: { id, repoConfig: { userId: user.id } },\n include: {\n repoConfig: { select: { repoOwner: true, repoName: true } },\n jobs: { orderBy: { createdAt: \"desc\" }, take: 10 },\n },\n });\n\n if (!preview) return makeResponse({ ctr, content: { code: 404, message: ERROR_MESSAGES.NOT_FOUND.message } });\n\n return makeResponse({\n ctr, content: {\n code: 200, data: {\n id: preview.id,\n prNumber: preview.prNumber,\n prTitle: preview.prTitle,\n commitSha: preview.commitSha,\n status: preview.status,\n instanceIp: preview.instanceIp,\n port: preview.port,\n logs: preview.logs,\n createdAt: preview.createdAt,\n updatedAt: preview.updatedAt,\n stoppedAt: preview.stoppedAt,\n lastActivityAt: preview.lastActivityAt,\n repoOwner: preview.repoConfig.repoOwner,\n repoName: preview.repoConfig.repoName,\n jobs: preview.jobs.map(j => ({\n id: j.id,\n type: j.type,\n status: j.status,\n createdAt: j.createdAt,\n startedAt: j.startedAt,\n finishedAt: j.finishedAt,\n error: j.error,\n })),\n }\n }\n });\n}\n\nexport async function stopPreviewRoute(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\n const preview = await prisma.preview.findFirst({\n where: { id, repoConfig: { userId: user.id } },\n });\n\n if (!preview) return makeResponse({ ctr, content: { code: 404, message: ERROR_MESSAGES.NOT_FOUND.message } });\n if (preview.status === \"STOPPED\") return makeResponse({ ctr, content: { code: 400, message: \"Already stopped\" } });\n\n await prisma.job.create({\n data: { previewId: id, type: \"STOP\", status: \"PENDING\", payload: { reason: \"Manual stop via UI\" } },\n });\n\n return makeResponse({ ctr, content: { code: 200, message: \"Stop job enqueued\" } });\n}\n\nexport async function previewLogsWs(ctr: any) {\n const auth = ctr.getAuth?.();\n if (!auth?.success) {\n ctr.close(1008, \"Unauthorized\");\n return;\n }\n\n const id = parseInt(ctr.params.get(\"id\") || \"0\", 10);\n const preview = await prisma.preview.findFirst({\n where: { id, repoConfig: { userId: auth.user.id } },\n });\n\n if (!preview) {\n ctr.close(1008, \"Not found\");\n return;\n }\n\n await ctr.print(JSON.stringify({ type: \"init\", logs: preview.logs }));\n\n const unsub = subscribeToLogs(id, (text) => {\n try {\n ctr.print(JSON.stringify({ type: \"append\", text }));\n } catch {}\n });\n\n ctr.$abort(unsub);\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAuB;AACvB,sBAA6B;AAC7B,oBAA+B;AAC/B,oBAAgC;AAEhC,SAAS,YAAY,KAAU;AAC7B,QAAM,OAAO,IAAI,UAAU;AAC3B,MAAI,CAAC,MAAM,QAAS,QAAO;AAC3B,SAAO,KAAK;AACd;AAEA,eAAsB,aAAa,KAAU;AAC3C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAE5G,QAAM,WAAW,MAAM,iBAAO,QAAQ,SAAS;AAAA,IAC7C,OAAO,EAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE;AAAA,IACzC,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,MAAM,UAAU,KAAK,EAAE,EAAE;AAAA,IACvE,SAAS,EAAE,WAAW,OAAO;AAAA,EAC/B,CAAC;AAED,aAAO,8BAAa;AAAA,IAClB;AAAA,IAAK,SAAS;AAAA,MACZ,MAAM;AAAA,MAAK,MAAM,SAAS,IAAI,QAAM;AAAA,QAClC,IAAI,EAAE;AAAA,QACN,UAAU,EAAE;AAAA,QACZ,SAAS,EAAE;AAAA,QACX,WAAW,EAAE;AAAA,QACb,QAAQ,EAAE;AAAA,QACV,YAAY,EAAE;AAAA,QACd,MAAM,EAAE;AAAA,QACR,WAAW,EAAE;AAAA,QACb,WAAW,EAAE;AAAA,QACb,gBAAgB,EAAE;AAAA,QAClB,WAAW,EAAE,WAAW;AAAA,QACxB,UAAU,EAAE,WAAW;AAAA,MACzB,EAAE;AAAA,IACJ;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,WAAW,KAAU;AACzC,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAE5G,QAAM,KAAK,SAAS,IAAI,OAAO,IAAI,IAAI,KAAK,KAAK,EAAE;AACnD,QAAM,UAAU,MAAM,iBAAO,QAAQ,UAAU;AAAA,IAC7C,OAAO,EAAE,IAAI,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE;AAAA,IAC7C,SAAS;AAAA,MACP,YAAY,EAAE,QAAQ,EAAE,WAAW,MAAM,UAAU,KAAK,EAAE;AAAA,MAC1D,MAAM,EAAE,SAAS,EAAE,WAAW,OAAO,GAAG,MAAM,GAAG;AAAA,IACnD;AAAA,EACF,CAAC;AAED,MAAI,CAAC,QAAS,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,UAAU,QAAQ,EAAE,CAAC;AAE5G,aAAO,8BAAa;AAAA,IAClB;AAAA,IAAK,SAAS;AAAA,MACZ,MAAM;AAAA,MAAK,MAAM;AAAA,QACf,IAAI,QAAQ;AAAA,QACZ,UAAU,QAAQ;AAAA,QAClB,SAAS,QAAQ;AAAA,QACjB,WAAW,QAAQ;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,YAAY,QAAQ;AAAA,QACpB,MAAM,QAAQ;AAAA,QACd,MAAM,QAAQ;AAAA,QACd,WAAW,QAAQ;AAAA,QACnB,WAAW,QAAQ;AAAA,QACnB,WAAW,QAAQ;AAAA,QACnB,gBAAgB,QAAQ;AAAA,QACxB,WAAW,QAAQ,WAAW;AAAA,QAC9B,UAAU,QAAQ,WAAW;AAAA,QAC7B,MAAM,QAAQ,KAAK,IAAI,QAAM;AAAA,UAC3B,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,QAAQ,EAAE;AAAA,UACV,WAAW,EAAE;AAAA,UACb,WAAW,EAAE;AAAA,UACb,YAAY,EAAE;AAAA,UACd,OAAO,EAAE;AAAA,QACX,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,iBAAiB,KAAU;AAC/C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAE5G,QAAM,KAAK,SAAS,IAAI,OAAO,IAAI,IAAI,KAAK,KAAK,EAAE;AACnD,QAAM,UAAU,MAAM,iBAAO,QAAQ,UAAU;AAAA,IAC7C,OAAO,EAAE,IAAI,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE;AAAA,EAC/C,CAAC;AAED,MAAI,CAAC,QAAS,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,UAAU,QAAQ,EAAE,CAAC;AAC5G,MAAI,QAAQ,WAAW,UAAW,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,kBAAkB,EAAE,CAAC;AAEjH,QAAM,iBAAO,IAAI,OAAO;AAAA,IACtB,MAAM,EAAE,WAAW,IAAI,MAAM,QAAQ,QAAQ,WAAW,SAAS,EAAE,QAAQ,qBAAqB,EAAE;AAAA,EACpG,CAAC;AAED,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,oBAAoB,EAAE,CAAC;AACnF;AAEA,eAAsB,cAAc,KAAU;AAC5C,QAAM,OAAO,IAAI,UAAU;AAC3B,MAAI,CAAC,MAAM,SAAS;AAClB,QAAI,MAAM,MAAM,cAAc;AAC9B;AAAA,EACF;AAEA,QAAM,KAAK,SAAS,IAAI,OAAO,IAAI,IAAI,KAAK,KAAK,EAAE;AACnD,QAAM,UAAU,MAAM,iBAAO,QAAQ,UAAU;AAAA,IAC7C,OAAO,EAAE,IAAI,YAAY,EAAE,QAAQ,KAAK,KAAK,GAAG,EAAE;AAAA,EACpD,CAAC;AAED,MAAI,CAAC,SAAS;AACZ,QAAI,MAAM,MAAM,WAAW;AAC3B;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,KAAK,UAAU,EAAE,MAAM,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC;AAEpE,QAAM,YAAQ,+BAAgB,IAAI,CAAC,SAAS;AAC1C,QAAI;AACF,UAAI,MAAM,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,IACpD,QAAQ;AAAA,IAAC;AAAA,EACX,CAAC;AAED,MAAI,OAAO,KAAK;AAClB;", - "names": [] -} diff --git a/backend/dist/routes/api/repos.js b/backend/dist/routes/api/repos.js deleted file mode 100644 index 9e4bd6ca..00000000 --- a/backend/dist/routes/api/repos.js +++ /dev/null @@ -1,180 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var repos_exports = {}; -__export(repos_exports, { - getRepoConfig: () => getRepoConfig, - listRepos: () => listRepos, - saveRepoConfig: () => saveRepoConfig, - toggleRepoEnabled: () => toggleRepoEnabled -}); -module.exports = __toCommonJS(repos_exports); -var import_db = require("../../lib/db"); -var import_response = require("../../lib/response"); -var import_errors = require("../../lib/errors"); -var import_gitea = require("../../services/gitea"); -var import_adminSettings = require("../../lib/adminSettings"); -var import_env = require("../../lib/env"); -function requireAuth(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) return null; - return auth.user; -} -async function listRepos(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const fullUser = await import_db.prisma.user.findUnique({ where: { id: user.id } }); - if (!fullUser?.giteaInstanceUrl || !fullUser?.giteaPAT) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Gitea credentials not configured" } }); - } - const giteaRepos = await (0, import_gitea.fetchUserRepos)(fullUser); - const configs = await import_db.prisma.repoConfig.findMany({ where: { userId: user.id } }); - const configMap = new Map(configs.map((c) => [`${c.repoOwner}/${c.repoName}`, c])); - const allOwners = [...new Set(giteaRepos.map((r) => r.full_name?.split("/")[0]).filter(Boolean))]; - const allConfigs = await import_db.prisma.repoConfig.findMany({ - where: { repoOwner: { in: allOwners } }, - select: { repoOwner: true, repoName: true, userId: true } - }); - const claimedByOthers = new Set( - allConfigs.filter((c) => c.userId !== user.id).map((c) => `${c.repoOwner}/${c.repoName}`) - ); - const result = giteaRepos.map((r) => { - const [owner, name] = (r.full_name || "").split("/"); - const key = `${owner}/${name}`; - const config = configMap.get(key); - const { giteaWebhookId, ...safeConfig } = config || {}; - return { - owner, - name, - fullName: r.full_name, - htmlUrl: r.html_url, - isEnabled: config?.isEnabled ?? false, - claimedByOther: claimedByOthers.has(key), - config: config ? safeConfig : null - }; - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: result } }); -} -async function getRepoConfig(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const owner = ctr.params.get("owner"); - const repo = ctr.params.get("repo"); - const config = await import_db.prisma.repoConfig.findFirst({ - where: { repoOwner: owner, repoName: repo, userId: user.id } - }); - if (!config) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: "Repo config not found" } }); - const { giteaWebhookId, ...safeConfig } = config; - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: safeConfig } }); -} -async function saveRepoConfig(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { owner, repo, ...configData } = body || {}; - if (!owner || !repo) return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "owner and repo required" } }); - const existing = await import_db.prisma.repoConfig.findFirst({ - where: { repoOwner: owner, repoName: repo } - }); - if (existing && existing.userId !== user.id) { - return (0, import_response.makeResponse)({ ctr, content: { code: 409, message: "This repo is already configured by another user." } }); - } - const settings = await (0, import_adminSettings.getAdminSettings)(); - const sanitized = { - repoOwner: owner, - repoName: repo, - userId: user.id, - instanceType: configData.instanceType ?? settings.defaultInstanceType, - inactivityHours: Math.min(72, Math.max(0.5, Number(configData.inactivityHours ?? 12))), - port: Number(configData.port ?? 3e3), - envVars: configData.envVars ?? {}, - useDockerCompose: Boolean(configData.useDockerCompose ?? false), - composeFilePath: configData.composeFilePath ?? null, - aptPackages: Array.isArray(configData.aptPackages) ? configData.aptPackages : [], - setupCommands: Array.isArray(configData.setupCommands) ? configData.setupCommands : [], - buildCommands: Array.isArray(configData.buildCommands) ? configData.buildCommands : [], - postBuildCommands: Array.isArray(configData.postBuildCommands) ? configData.postBuildCommands : [], - runCommand: configData.runCommand ?? null, - denyList: Array.isArray(configData.denyList) ? configData.denyList : [] - }; - let config; - if (existing) { - config = await import_db.prisma.repoConfig.update({ where: { id: existing.id }, data: sanitized }); - } else { - config = await import_db.prisma.repoConfig.create({ data: sanitized }); - } - const { giteaWebhookId, ...safeConfig } = config; - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: safeConfig } }); -} -async function toggleRepoEnabled(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { owner, repo, enabled } = body || {}; - if (!owner || !repo || enabled === void 0) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "owner, repo, enabled required" } }); - } - const fullUser = await import_db.prisma.user.findUnique({ where: { id: user.id } }); - if (!fullUser?.giteaInstanceUrl || !fullUser?.giteaPAT) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Gitea credentials not configured" } }); - } - let config = await import_db.prisma.repoConfig.findFirst({ where: { repoOwner: owner, repoName: repo } }); - if (config && config.userId !== user.id) { - return (0, import_response.makeResponse)({ ctr, content: { code: 409, message: "This repo is already configured by another user." } }); - } - const webhookToken = await import_db.prisma.webhookToken.findUnique({ where: { userId: user.id } }); - if (!webhookToken) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "No webhook token configured. Go to Settings to generate one." } }); - } - if (enabled) { - if (!config) { - config = await import_db.prisma.repoConfig.create({ - data: { repoOwner: owner, repoName: repo, userId: user.id, isEnabled: false } - }); - } - const webhookUrl = `${import_env.env.PP_BASE_URL}/webhook/${user.id}`; - const hookId = await (0, import_gitea.registerWebhook)(fullUser, owner, repo, webhookUrl, webhookToken.token); - await import_db.prisma.repoConfig.update({ - where: { id: config.id }, - data: { isEnabled: true, giteaWebhookId: String(hookId) } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Repo enabled and webhook registered" } }); - } else { - if (!config) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: "Repo config not found" } }); - if (config.giteaWebhookId) { - try { - await (0, import_gitea.deleteWebhook)(fullUser, owner, repo, config.giteaWebhookId); - } catch (e) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: `Failed to delete Gitea webhook: ${e.message}` } }); - } - } - await import_db.prisma.repoConfig.update({ - where: { id: config.id }, - data: { isEnabled: false, giteaWebhookId: null } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Repo disabled and webhook removed" } }); - } -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - getRepoConfig, - listRepos, - saveRepoConfig, - toggleRepoEnabled -}); -//# sourceMappingURL=repos.js.map diff --git a/backend/dist/routes/api/repos.js.map b/backend/dist/routes/api/repos.js.map deleted file mode 100644 index 6becbe92..00000000 --- a/backend/dist/routes/api/repos.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/routes/api/repos.ts"], - "sourcesContent": ["import { prisma } from \"../../lib/db\";\nimport { makeResponse } from \"../../lib/response\";\nimport { ERROR_MESSAGES } from \"../../lib/errors\";\nimport { fetchUserRepos, registerWebhook, deleteWebhook } from \"../../services/gitea\";\nimport { getAdminSettings } from \"../../lib/adminSettings\";\nimport { env } from \"../../lib/env\";\n\nfunction requireAuth(ctr: any) {\n const auth = ctr.getAuth?.();\n if (!auth?.success) return null;\n return auth.user;\n}\n\nexport async function listRepos(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const fullUser = await prisma.user.findUnique({ where: { id: user.id } });\n if (!fullUser?.giteaInstanceUrl || !fullUser?.giteaPAT) {\n return makeResponse({ ctr, content: { code: 400, message: \"Gitea credentials not configured\" } });\n }\n\n const giteaRepos = await fetchUserRepos(fullUser as any);\n const configs = await prisma.repoConfig.findMany({ where: { userId: user.id } });\n const configMap = new Map(configs.map(c => [`${c.repoOwner}/${c.repoName}`, c]));\n\n const allOwners = [...new Set(giteaRepos.map((r: any) => r.full_name?.split(\"/\")[0]).filter(Boolean))];\n const allConfigs = await prisma.repoConfig.findMany({\n where: { repoOwner: { in: allOwners } },\n select: { repoOwner: true, repoName: true, userId: true },\n });\n const claimedByOthers = new Set(\n allConfigs.filter(c => c.userId !== user.id).map(c => `${c.repoOwner}/${c.repoName}`)\n );\n\n const result = giteaRepos.map((r: any) => {\n const [owner, name] = (r.full_name || \"\").split(\"/\");\n const key = `${owner}/${name}`;\n const config = configMap.get(key);\n const { giteaWebhookId, ...safeConfig } = config || {} as any;\n return {\n owner,\n name,\n fullName: r.full_name,\n htmlUrl: r.html_url,\n isEnabled: config?.isEnabled ?? false,\n claimedByOther: claimedByOthers.has(key),\n config: config ? safeConfig : null,\n };\n });\n\n return makeResponse({ ctr, content: { code: 200, data: result } });\n}\n\nexport async function getRepoConfig(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const owner = ctr.params.get(\"owner\");\n const repo = ctr.params.get(\"repo\");\n\n const config = await prisma.repoConfig.findFirst({\n where: { repoOwner: owner, repoName: repo, userId: user.id },\n });\n if (!config) return makeResponse({ ctr, content: { code: 404, message: \"Repo config not found\" } });\n\n const { giteaWebhookId, ...safeConfig } = config;\n return makeResponse({ ctr, content: { code: 200, data: safeConfig } });\n}\n\nexport async function saveRepoConfig(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const body = await ctr.body();\n const { owner, repo, ...configData } = body || {};\n if (!owner || !repo) return makeResponse({ ctr, content: { code: 400, message: \"owner and repo required\" } });\n\n const existing = await prisma.repoConfig.findFirst({\n where: { repoOwner: owner, repoName: repo },\n });\n\n if (existing && existing.userId !== user.id) {\n return makeResponse({ ctr, content: { code: 409, message: \"This repo is already configured by another user.\" } });\n }\n\n const settings = await getAdminSettings();\n\n const sanitized = {\n repoOwner: owner,\n repoName: repo,\n userId: user.id,\n instanceType: configData.instanceType ?? settings.defaultInstanceType,\n inactivityHours: Math.min(72, Math.max(0.5, Number(configData.inactivityHours ?? 12))),\n port: Number(configData.port ?? 3000),\n envVars: configData.envVars ?? {},\n useDockerCompose: Boolean(configData.useDockerCompose ?? false),\n composeFilePath: configData.composeFilePath ?? null,\n aptPackages: Array.isArray(configData.aptPackages) ? configData.aptPackages : [],\n setupCommands: Array.isArray(configData.setupCommands) ? configData.setupCommands : [],\n buildCommands: Array.isArray(configData.buildCommands) ? configData.buildCommands : [],\n postBuildCommands: Array.isArray(configData.postBuildCommands) ? configData.postBuildCommands : [],\n runCommand: configData.runCommand ?? null,\n denyList: Array.isArray(configData.denyList) ? configData.denyList : [],\n };\n\n let config;\n if (existing) {\n config = await prisma.repoConfig.update({ where: { id: existing.id }, data: sanitized });\n } else {\n config = await prisma.repoConfig.create({ data: sanitized });\n }\n\n const { giteaWebhookId, ...safeConfig } = config;\n return makeResponse({ ctr, content: { code: 200, data: safeConfig } });\n}\n\nexport async function toggleRepoEnabled(ctr: any) {\n const user = requireAuth(ctr);\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\n\n const body = await ctr.body();\n const { owner, repo, enabled } = body || {};\n if (!owner || !repo || enabled === undefined) {\n return makeResponse({ ctr, content: { code: 400, message: \"owner, repo, enabled required\" } });\n }\n\n const fullUser = await prisma.user.findUnique({ where: { id: user.id } });\n if (!fullUser?.giteaInstanceUrl || !fullUser?.giteaPAT) {\n return makeResponse({ ctr, content: { code: 400, message: \"Gitea credentials not configured\" } });\n }\n\n let config = await prisma.repoConfig.findFirst({ where: { repoOwner: owner, repoName: repo } });\n if (config && config.userId !== user.id) {\n return makeResponse({ ctr, content: { code: 409, message: \"This repo is already configured by another user.\" } });\n }\n\n const webhookToken = await prisma.webhookToken.findUnique({ where: { userId: user.id } });\n if (!webhookToken) {\n return makeResponse({ ctr, content: { code: 400, message: \"No webhook token configured. Go to Settings to generate one.\" } });\n }\n\n if (enabled) {\n if (!config) {\n config = await prisma.repoConfig.create({\n data: { repoOwner: owner, repoName: repo, userId: user.id, isEnabled: false },\n });\n }\n\n const webhookUrl = `${env.PP_BASE_URL}/webhook/${user.id}`;\n const hookId = await registerWebhook(fullUser as any, owner, repo, webhookUrl, webhookToken.token);\n await prisma.repoConfig.update({\n where: { id: config.id },\n data: { isEnabled: true, giteaWebhookId: String(hookId) },\n });\n return makeResponse({ ctr, content: { code: 200, message: \"Repo enabled and webhook registered\" } });\n } else {\n if (!config) return makeResponse({ ctr, content: { code: 404, message: \"Repo config not found\" } });\n if (config.giteaWebhookId) {\n try {\n await deleteWebhook(fullUser as any, owner, repo, config.giteaWebhookId);\n } catch (e: any) {\n return makeResponse({ ctr, content: { code: 400, message: `Failed to delete Gitea webhook: ${e.message}` } });\n }\n }\n await prisma.repoConfig.update({\n where: { id: config.id },\n data: { isEnabled: false, giteaWebhookId: null },\n });\n return makeResponse({ ctr, content: { code: 200, message: \"Repo disabled and webhook removed\" } });\n }\n}\n"], - "mappings": "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", - "names": [] -} diff --git a/backend/dist/routes/api/user.js b/backend/dist/routes/api/user.js deleted file mode 100644 index b2e8c5f7..00000000 --- a/backend/dist/routes/api/user.js +++ /dev/null @@ -1,204 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var user_exports = {}; -__export(user_exports, { - getUserSettings: () => getUserSettings, - getWebhookSecret: () => getWebhookSecret, - regenerateWebhookSecret: () => regenerateWebhookSecret, - updateAws: () => updateAws, - updateGitea: () => updateGitea, - updatePassword: () => updatePassword, - updateUsername: () => updateUsername -}); -module.exports = __toCommonJS(user_exports); -var import_bcryptjs = __toESM(require("bcryptjs")); -var import_crypto = require("crypto"); -var import_db = require("../../lib/db"); -var import_response = require("../../lib/response"); -var import_errors = require("../../lib/errors"); -var import_encryption = require("../../lib/encryption"); -var import_gitea = require("../../services/gitea"); -var import_ec2 = require("../../services/ec2"); -var import_env = require("../../lib/env"); -function requireAuth(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) return null; - return auth.user; -} -async function getUserSettings(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: import_errors.ERROR_MESSAGES.UNAUTHORIZED.code, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const webhookToken = await import_db.prisma.webhookToken.findUnique({ where: { userId: user.id } }); - const fullUser = await import_db.prisma.user.findUnique({ where: { id: user.id } }); - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - data: { - id: user.id, - username: user.username, - giteaUsername: fullUser?.giteaUsername, - giteaInstanceUrl: fullUser?.giteaInstanceUrl, - giteaPatSet: !!fullUser?.giteaPAT, - awsAccessKeyId: fullUser?.awsAccessKeyId ? "****" : null, - awsRegion: fullUser?.awsRegion, - webhookUrl: `${import_env.env.PP_BASE_URL}/webhook/${user.id}`, - webhookSecret: webhookToken?.token ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : null, - webhookTokenExists: !!webhookToken - } - } - }); -} -async function updateUsername(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { username } = body || {}; - if (!username || typeof username !== "string") return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Username required" } }); - const existing = await import_db.prisma.user.findFirst({ where: { username, id: { not: user.id } } }); - if (existing) return (0, import_response.makeResponse)({ ctr, content: { code: 409, message: "Username already taken" } }); - await import_db.prisma.user.update({ where: { id: user.id }, data: { username } }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Username updated" } }); -} -async function updatePassword(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { currentPassword, newPassword } = body || {}; - if (!currentPassword || !newPassword) return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Current and new passwords required" } }); - const fullUser = await import_db.prisma.user.findUnique({ where: { id: user.id } }); - if (!fullUser) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: "User not found" } }); - const valid = await import_bcryptjs.default.compare(currentPassword, fullUser.passwordHash); - if (!valid) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: "Current password incorrect" } }); - const hash = await import_bcryptjs.default.hash(newPassword, 12); - await import_db.prisma.user.update({ where: { id: user.id }, data: { passwordHash: hash } }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Password updated" } }); -} -async function updateGitea(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { giteaInstanceUrl, giteaUsername, giteaPAT } = body || {}; - if (!giteaInstanceUrl || !giteaUsername) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Gitea URL and username required" } }); - } - const cleanUrl = giteaInstanceUrl.replace(/\/+$/, ""); - const validation = await (0, import_gitea.validateGiteaUrl)(cleanUrl); - if (!validation.success) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: `Gitea validation failed: ${validation.error}` } }); - } - const data = { giteaInstanceUrl: cleanUrl, giteaUsername }; - if (giteaPAT) data.giteaPAT = (0, import_encryption.encrypt)(giteaPAT); - await import_db.prisma.user.update({ where: { id: user.id }, data }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: `Connected to Gitea ${validation.version}`, data: { version: validation.version } } }); -} -async function updateAws(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const body = await ctr.body(); - const { awsAccessKeyId, awsSecretAccessKey, awsRegion } = body || {}; - if (!awsAccessKeyId || !awsSecretAccessKey || !awsRegion) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "AWS credentials and region required" } }); - } - const tempUser = { - ...user, - awsAccessKeyId: (0, import_encryption.encrypt)(awsAccessKeyId), - awsSecretAccessKey: (0, import_encryption.encrypt)(awsSecretAccessKey), - awsRegion - }; - const validation = await (0, import_ec2.validateAwsCredentials)(tempUser); - if (!validation.success) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: `AWS validation failed: ${validation.error}` } }); - } - await import_db.prisma.user.update({ - where: { id: user.id }, - data: { - awsAccessKeyId: (0, import_encryption.encrypt)(awsAccessKeyId), - awsSecretAccessKey: (0, import_encryption.encrypt)(awsSecretAccessKey), - awsRegion - } - }); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: `Connected as ${validation.arn}`, data: { arn: validation.arn } } }); -} -async function getWebhookSecret(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - let token = await import_db.prisma.webhookToken.findUnique({ where: { userId: user.id } }); - if (!token) { - const secret = (0, import_crypto.randomBytes)(32).toString("hex"); - token = await import_db.prisma.webhookToken.create({ data: { userId: user.id, token: secret } }); - } - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: { token: token.token } } }); -} -async function regenerateWebhookSecret(ctr) { - const user = requireAuth(ctr); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - const newSecret = (0, import_crypto.randomBytes)(32).toString("hex"); - await import_db.prisma.webhookToken.upsert({ - where: { userId: user.id }, - update: { token: newSecret }, - create: { userId: user.id, token: newSecret } - }); - const fullUser = await import_db.prisma.user.findUnique({ where: { id: user.id } }); - if (!fullUser?.giteaInstanceUrl) { - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Secret regenerated (no Gitea hooks to update)", data: { token: newSecret } } }); - } - const configs = await import_db.prisma.repoConfig.findMany({ - where: { userId: user.id, giteaWebhookId: { not: null } } - }); - const { updateWebhookSecret } = await import("../../services/gitea"); - const webhookUrl = `${import_env.env.PP_BASE_URL}/webhook/${user.id}`; - const errors = []; - for (const config of configs) { - try { - await updateWebhookSecret(fullUser, config.repoOwner, config.repoName, config.giteaWebhookId, webhookUrl, newSecret); - } catch (e) { - errors.push(`${config.repoOwner}/${config.repoName}: ${e.message}`); - } - } - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - message: errors.length ? `Secret regenerated with ${errors.length} hook update errors` : "Secret regenerated and all hooks updated", - data: { token: newSecret, errors } - } - }); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - getUserSettings, - getWebhookSecret, - regenerateWebhookSecret, - updateAws, - updateGitea, - updatePassword, - updateUsername -}); -//# sourceMappingURL=user.js.map diff --git a/backend/dist/routes/api/user.js.map b/backend/dist/routes/api/user.js.map deleted file mode 100644 index 29f86d6f..00000000 --- a/backend/dist/routes/api/user.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../src/routes/api/user.ts"], - "sourcesContent": ["import bcrypt from \"bcryptjs\";\r\nimport { randomBytes } from \"crypto\";\r\nimport { prisma } from \"../../lib/db\";\r\nimport { makeResponse } from \"../../lib/response\";\r\nimport { ERROR_MESSAGES } from \"../../lib/errors\";\r\nimport { encrypt, decrypt } from \"../../lib/encryption\";\r\nimport { validateGiteaUrl } from \"../../services/gitea\";\r\nimport { validateAwsCredentials } from \"../../services/ec2\";\r\nimport { env } from \"../../lib/env\";\r\n\r\nfunction requireAuth(ctr: any) {\r\n const auth = ctr.getAuth?.();\r\n if (!auth?.success) return null;\r\n return auth.user;\r\n}\r\n\r\nexport async function getUserSettings(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: ERROR_MESSAGES.UNAUTHORIZED.code, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n\r\n const webhookToken = await prisma.webhookToken.findUnique({ where: { userId: user.id } });\r\n const fullUser = await prisma.user.findUnique({ where: { id: user.id } });\r\n\r\n return makeResponse({\r\n ctr, content: {\r\n code: 200, data: {\r\n id: user.id,\r\n username: user.username,\r\n giteaUsername: fullUser?.giteaUsername,\r\n giteaInstanceUrl: fullUser?.giteaInstanceUrl,\r\n giteaPatSet: !!fullUser?.giteaPAT,\r\n awsAccessKeyId: fullUser?.awsAccessKeyId ? \"****\" : null,\r\n awsRegion: fullUser?.awsRegion,\r\n webhookUrl: `${env.PP_BASE_URL}/webhook/${user.id}`,\r\n webhookSecret: webhookToken?.token ? \"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\" : null,\r\n webhookTokenExists: !!webhookToken,\r\n }\r\n }\r\n });\r\n}\r\n\r\nexport async function updateUsername(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n const body = await ctr.body();\r\n const { username } = body || {};\r\n if (!username || typeof username !== \"string\") return makeResponse({ ctr, content: { code: 400, message: \"Username required\" } });\r\n\r\n const existing = await prisma.user.findFirst({ where: { username, id: { not: user.id } } });\r\n if (existing) return makeResponse({ ctr, content: { code: 409, message: \"Username already taken\" } });\r\n\r\n await prisma.user.update({ where: { id: user.id }, data: { username } });\r\n return makeResponse({ ctr, content: { code: 200, message: \"Username updated\" } });\r\n}\r\n\r\nexport async function updatePassword(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n const body = await ctr.body();\r\n const { currentPassword, newPassword } = body || {};\r\n if (!currentPassword || !newPassword) return makeResponse({ ctr, content: { code: 400, message: \"Current and new passwords required\" } });\r\n\r\n const fullUser = await prisma.user.findUnique({ where: { id: user.id } });\r\n if (!fullUser) return makeResponse({ ctr, content: { code: 404, message: \"User not found\" } });\r\n\r\n const valid = await bcrypt.compare(currentPassword, fullUser.passwordHash);\r\n if (!valid) return makeResponse({ ctr, content: { code: 401, message: \"Current password incorrect\" } });\r\n\r\n const hash = await bcrypt.hash(newPassword, 12);\r\n await prisma.user.update({ where: { id: user.id }, data: { passwordHash: hash } });\r\n return makeResponse({ ctr, content: { code: 200, message: \"Password updated\" } });\r\n}\r\n\r\nexport async function updateGitea(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n const body = await ctr.body();\r\n const { giteaInstanceUrl, giteaUsername, giteaPAT } = body || {};\r\n\r\n if (!giteaInstanceUrl || !giteaUsername) {\r\n return makeResponse({ ctr, content: { code: 400, message: \"Gitea URL and username required\" } });\r\n }\r\n\r\n const cleanUrl = giteaInstanceUrl.replace(/\\/+$/, \"\");\r\n const validation = await validateGiteaUrl(cleanUrl);\r\n if (!validation.success) {\r\n return makeResponse({ ctr, content: { code: 400, message: `Gitea validation failed: ${validation.error}` } });\r\n }\r\n\r\n const data: any = { giteaInstanceUrl: cleanUrl, giteaUsername };\r\n if (giteaPAT) data.giteaPAT = encrypt(giteaPAT);\r\n\r\n await prisma.user.update({ where: { id: user.id }, data });\r\n return makeResponse({ ctr, content: { code: 200, message: `Connected to Gitea ${validation.version}`, data: { version: validation.version } } });\r\n}\r\n\r\nexport async function updateAws(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n const body = await ctr.body();\r\n const { awsAccessKeyId, awsSecretAccessKey, awsRegion } = body || {};\r\n\r\n if (!awsAccessKeyId || !awsSecretAccessKey || !awsRegion) {\r\n return makeResponse({ ctr, content: { code: 400, message: \"AWS credentials and region required\" } });\r\n }\r\n\r\n const tempUser = {\r\n ...user,\r\n awsAccessKeyId: encrypt(awsAccessKeyId),\r\n awsSecretAccessKey: encrypt(awsSecretAccessKey),\r\n awsRegion,\r\n };\r\n const validation = await validateAwsCredentials(tempUser as any);\r\n if (!validation.success) {\r\n return makeResponse({ ctr, content: { code: 400, message: `AWS validation failed: ${validation.error}` } });\r\n }\r\n\r\n await prisma.user.update({\r\n where: { id: user.id },\r\n data: {\r\n awsAccessKeyId: encrypt(awsAccessKeyId),\r\n awsSecretAccessKey: encrypt(awsSecretAccessKey),\r\n awsRegion,\r\n },\r\n });\r\n\r\n return makeResponse({ ctr, content: { code: 200, message: `Connected as ${validation.arn}`, data: { arn: validation.arn } } });\r\n}\r\n\r\nexport async function getWebhookSecret(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n\r\n let token = await prisma.webhookToken.findUnique({ where: { userId: user.id } });\r\n if (!token) {\r\n const secret = randomBytes(32).toString(\"hex\");\r\n token = await prisma.webhookToken.create({ data: { userId: user.id, token: secret } });\r\n }\r\n\r\n return makeResponse({ ctr, content: { code: 200, data: { token: token.token } } });\r\n}\r\n\r\nexport async function regenerateWebhookSecret(ctr: any) {\r\n const user = requireAuth(ctr);\r\n if (!user) return makeResponse({ ctr, content: { code: 401, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n\r\n const newSecret = randomBytes(32).toString(\"hex\");\r\n await prisma.webhookToken.upsert({\r\n where: { userId: user.id },\r\n update: { token: newSecret },\r\n create: { userId: user.id, token: newSecret },\r\n });\r\n\r\n const fullUser = await prisma.user.findUnique({ where: { id: user.id } });\r\n if (!fullUser?.giteaInstanceUrl) {\r\n return makeResponse({ ctr, content: { code: 200, message: \"Secret regenerated (no Gitea hooks to update)\", data: { token: newSecret } } });\r\n }\r\n\r\n const configs = await prisma.repoConfig.findMany({\r\n where: { userId: user.id, giteaWebhookId: { not: null } },\r\n });\r\n\r\n const { updateWebhookSecret } = await import(\"../../services/gitea\");\r\n const webhookUrl = `${env.PP_BASE_URL}/webhook/${user.id}`;\r\n const errors: string[] = [];\r\n\r\n for (const config of configs) {\r\n try {\r\n await updateWebhookSecret(fullUser as any, config.repoOwner, config.repoName, config.giteaWebhookId!, webhookUrl, newSecret);\r\n } catch (e: any) {\r\n errors.push(`${config.repoOwner}/${config.repoName}: ${e.message}`);\r\n }\r\n }\r\n\r\n return makeResponse({\r\n ctr, content: {\r\n code: 200,\r\n message: errors.length ? `Secret regenerated with ${errors.length} hook update errors` : \"Secret regenerated and all hooks updated\",\r\n data: { token: newSecret, errors },\r\n }\r\n });\r\n}\r\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAmB;AACnB,oBAA4B;AAC5B,gBAAuB;AACvB,sBAA6B;AAC7B,oBAA+B;AAC/B,wBAAiC;AACjC,mBAAiC;AACjC,iBAAuC;AACvC,iBAAoB;AAEpB,SAAS,YAAY,KAAU;AAC7B,QAAM,OAAO,IAAI,UAAU;AAC3B,MAAI,CAAC,MAAM,QAAS,QAAO;AAC3B,SAAO,KAAK;AACd;AAEA,eAAsB,gBAAgB,KAAU;AAC9C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,6BAAe,aAAa,MAAM,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAEzI,QAAM,eAAe,MAAM,iBAAO,aAAa,WAAW,EAAE,OAAO,EAAE,QAAQ,KAAK,GAAG,EAAE,CAAC;AACxF,QAAM,WAAW,MAAM,iBAAO,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC;AAExE,aAAO,8BAAa;AAAA,IAClB;AAAA,IAAK,SAAS;AAAA,MACZ,MAAM;AAAA,MAAK,MAAM;AAAA,QACf,IAAI,KAAK;AAAA,QACT,UAAU,KAAK;AAAA,QACf,eAAe,UAAU;AAAA,QACzB,kBAAkB,UAAU;AAAA,QAC5B,aAAa,CAAC,CAAC,UAAU;AAAA,QACzB,gBAAgB,UAAU,iBAAiB,SAAS;AAAA,QACpD,WAAW,UAAU;AAAA,QACrB,YAAY,GAAG,eAAI,WAAW,YAAY,KAAK,EAAE;AAAA,QACjD,eAAe,cAAc,QAAQ,qDAAa;AAAA,QAClD,oBAAoB,CAAC,CAAC;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,eAAe,KAAU;AAC7C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAC5G,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAM,EAAE,SAAS,IAAI,QAAQ,CAAC;AAC9B,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,oBAAoB,EAAE,CAAC;AAEhI,QAAM,WAAW,MAAM,iBAAO,KAAK,UAAU,EAAE,OAAO,EAAE,UAAU,IAAI,EAAE,KAAK,KAAK,GAAG,EAAE,EAAE,CAAC;AAC1F,MAAI,SAAU,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,yBAAyB,EAAE,CAAC;AAEpG,QAAM,iBAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC;AACvE,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,mBAAmB,EAAE,CAAC;AAClF;AAEA,eAAsB,eAAe,KAAU;AAC7C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAC5G,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAM,EAAE,iBAAiB,YAAY,IAAI,QAAQ,CAAC;AAClD,MAAI,CAAC,mBAAmB,CAAC,YAAa,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,qCAAqC,EAAE,CAAC;AAExI,QAAM,WAAW,MAAM,iBAAO,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC;AACxE,MAAI,CAAC,SAAU,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,iBAAiB,EAAE,CAAC;AAE7F,QAAM,QAAQ,MAAM,gBAAAA,QAAO,QAAQ,iBAAiB,SAAS,YAAY;AACzE,MAAI,CAAC,MAAO,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAA6B,EAAE,CAAC;AAEtG,QAAM,OAAO,MAAM,gBAAAA,QAAO,KAAK,aAAa,EAAE;AAC9C,QAAM,iBAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,GAAG,MAAM,EAAE,cAAc,KAAK,EAAE,CAAC;AACjF,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,mBAAmB,EAAE,CAAC;AAClF;AAEA,eAAsB,YAAY,KAAU;AAC1C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAC5G,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAM,EAAE,kBAAkB,eAAe,SAAS,IAAI,QAAQ,CAAC;AAE/D,MAAI,CAAC,oBAAoB,CAAC,eAAe;AACvC,eAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,kCAAkC,EAAE,CAAC;AAAA,EACjG;AAEA,QAAM,WAAW,iBAAiB,QAAQ,QAAQ,EAAE;AACpD,QAAM,aAAa,UAAM,+BAAiB,QAAQ;AAClD,MAAI,CAAC,WAAW,SAAS;AACvB,eAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,4BAA4B,WAAW,KAAK,GAAG,EAAE,CAAC;AAAA,EAC9G;AAEA,QAAM,OAAY,EAAE,kBAAkB,UAAU,cAAc;AAC9D,MAAI,SAAU,MAAK,eAAW,2BAAQ,QAAQ;AAE9C,QAAM,iBAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,GAAG,KAAK,CAAC;AACzD,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,sBAAsB,WAAW,OAAO,IAAI,MAAM,EAAE,SAAS,WAAW,QAAQ,EAAE,EAAE,CAAC;AACjJ;AAEA,eAAsB,UAAU,KAAU;AACxC,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAC5G,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAM,EAAE,gBAAgB,oBAAoB,UAAU,IAAI,QAAQ,CAAC;AAEnE,MAAI,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,WAAW;AACxD,eAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,sCAAsC,EAAE,CAAC;AAAA,EACrG;AAEA,QAAM,WAAW;AAAA,IACf,GAAG;AAAA,IACH,oBAAgB,2BAAQ,cAAc;AAAA,IACtC,wBAAoB,2BAAQ,kBAAkB;AAAA,IAC9C;AAAA,EACF;AACA,QAAM,aAAa,UAAM,mCAAuB,QAAe;AAC/D,MAAI,CAAC,WAAW,SAAS;AACvB,eAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,0BAA0B,WAAW,KAAK,GAAG,EAAE,CAAC;AAAA,EAC5G;AAEA,QAAM,iBAAO,KAAK,OAAO;AAAA,IACvB,OAAO,EAAE,IAAI,KAAK,GAAG;AAAA,IACrB,MAAM;AAAA,MACJ,oBAAgB,2BAAQ,cAAc;AAAA,MACtC,wBAAoB,2BAAQ,kBAAkB;AAAA,MAC9C;AAAA,IACF;AAAA,EACF,CAAC;AAED,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,gBAAgB,WAAW,GAAG,IAAI,MAAM,EAAE,KAAK,WAAW,IAAI,EAAE,EAAE,CAAC;AAC/H;AAEA,eAAsB,iBAAiB,KAAU;AAC/C,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAE5G,MAAI,QAAQ,MAAM,iBAAO,aAAa,WAAW,EAAE,OAAO,EAAE,QAAQ,KAAK,GAAG,EAAE,CAAC;AAC/E,MAAI,CAAC,OAAO;AACV,UAAM,aAAS,2BAAY,EAAE,EAAE,SAAS,KAAK;AAC7C,YAAQ,MAAM,iBAAO,aAAa,OAAO,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,OAAO,OAAO,EAAE,CAAC;AAAA,EACvF;AAEA,aAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,MAAM,EAAE,OAAO,MAAM,MAAM,EAAE,EAAE,CAAC;AACnF;AAEA,eAAsB,wBAAwB,KAAU;AACtD,QAAM,OAAO,YAAY,GAAG;AAC5B,MAAI,CAAC,KAAM,YAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,6BAAe,aAAa,QAAQ,EAAE,CAAC;AAE5G,QAAM,gBAAY,2BAAY,EAAE,EAAE,SAAS,KAAK;AAChD,QAAM,iBAAO,aAAa,OAAO;AAAA,IAC/B,OAAO,EAAE,QAAQ,KAAK,GAAG;AAAA,IACzB,QAAQ,EAAE,OAAO,UAAU;AAAA,IAC3B,QAAQ,EAAE,QAAQ,KAAK,IAAI,OAAO,UAAU;AAAA,EAC9C,CAAC;AAED,QAAM,WAAW,MAAM,iBAAO,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,KAAK,GAAG,EAAE,CAAC;AACxE,MAAI,CAAC,UAAU,kBAAkB;AAC/B,eAAO,8BAAa,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,iDAAiD,MAAM,EAAE,OAAO,UAAU,EAAE,EAAE,CAAC;AAAA,EAC3I;AAEA,QAAM,UAAU,MAAM,iBAAO,WAAW,SAAS;AAAA,IAC/C,OAAO,EAAE,QAAQ,KAAK,IAAI,gBAAgB,EAAE,KAAK,KAAK,EAAE;AAAA,EAC1D,CAAC;AAED,QAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,sBAAsB;AACnE,QAAM,aAAa,GAAG,eAAI,WAAW,YAAY,KAAK,EAAE;AACxD,QAAM,SAAmB,CAAC;AAE1B,aAAW,UAAU,SAAS;AAC5B,QAAI;AACF,YAAM,oBAAoB,UAAiB,OAAO,WAAW,OAAO,UAAU,OAAO,gBAAiB,YAAY,SAAS;AAAA,IAC7H,SAAS,GAAQ;AACf,aAAO,KAAK,GAAG,OAAO,SAAS,IAAI,OAAO,QAAQ,KAAK,EAAE,OAAO,EAAE;AAAA,IACpE;AAAA,EACF;AAEA,aAAO,8BAAa;AAAA,IAClB;AAAA,IAAK,SAAS;AAAA,MACZ,MAAM;AAAA,MACN,SAAS,OAAO,SAAS,2BAA2B,OAAO,MAAM,wBAAwB;AAAA,MACzF,MAAM,EAAE,OAAO,WAAW,OAAO;AAAA,IACnC;AAAA,EACF,CAAC;AACH;", - "names": ["bcrypt"] -} diff --git a/backend/dist/routes/auth.js b/backend/dist/routes/auth.js deleted file mode 100644 index 1d9e7e9e..00000000 --- a/backend/dist/routes/auth.js +++ /dev/null @@ -1,161 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var auth_exports = {}; -__export(auth_exports, { - firstUserHandler: () => firstUserHandler, - loginHandler: () => loginHandler, - logoutHandler: () => logoutHandler, - meHandler: () => meHandler, - setupStatusHandler: () => setupStatusHandler -}); -module.exports = __toCommonJS(auth_exports); -var import_crypto = require("crypto"); -var import_bcryptjs = __toESM(require("bcryptjs")); -var import_rjweb_server = require("rjweb-server"); -var import_db = require("../lib/db"); -var import_response = require("../lib/response"); -var import_errors = require("../lib/errors"); -var import_logger = require("../lib/logger"); -const log = (0, import_logger.createLogger)("AUTH_ROUTE"); -const COOKIE_NAME = "pp_session"; -const COOKIE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3; -async function loginHandler(ctr) { - let body; - try { - body = await ctr.body(); - } catch { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Invalid body" } }); - } - const { username, password } = body || {}; - if (!username || !password) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Username and password required" } }); - } - const user = await import_db.prisma.user.findUnique({ where: { username } }); - if (!user) { - return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: "Invalid credentials" } }); - } - const valid = await import_bcryptjs.default.compare(password, user.passwordHash); - if (!valid) { - return (0, import_response.makeResponse)({ ctr, content: { code: 401, message: "Invalid credentials" } }); - } - const sessionHash = (0, import_crypto.randomBytes)(32).toString("hex"); - await import_db.prisma.session.create({ data: { hash: sessionHash, userId: user.id } }); - ctr.cookies.set( - COOKIE_NAME, - new import_rjweb_server.Cookie(sessionHash, { - httpOnly: true, - expires: new Date(Date.now() + COOKIE_MAX_AGE_MS), - path: "/", - sameSite: "Lax" - }) - ); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: { id: user.id, username: user.username, isAdmin: user.isAdmin } } }); -} -async function logoutHandler(ctr) { - const auth = ctr.getAuth?.(); - if (auth?.success) { - await import_db.prisma.session.delete({ where: { id: auth.sessionId } }).catch(() => { - }); - } - ctr.cookies.set(COOKIE_NAME, new import_rjweb_server.Cookie("", { expires: /* @__PURE__ */ new Date(0), path: "/" })); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, message: "Logged out" } }); -} -async function meHandler(ctr) { - const auth = ctr.getAuth?.(); - if (!auth?.success) { - return (0, import_response.makeResponse)({ ctr, content: { code: import_errors.ERROR_MESSAGES.UNAUTHORIZED.code, message: import_errors.ERROR_MESSAGES.UNAUTHORIZED.message } }); - } - const user = await import_db.prisma.user.findUnique({ where: { id: auth.user.id } }); - if (!user) return (0, import_response.makeResponse)({ ctr, content: { code: 404, message: "User not found" } }); - return (0, import_response.makeResponse)({ - ctr, - content: { - code: 200, - data: { - id: user.id, - username: user.username, - isAdmin: user.isAdmin, - isFounder: user.isFounder, - giteaUsername: user.giteaUsername, - giteaInstanceUrl: user.giteaInstanceUrl, - giteaPatSet: !!user.giteaPAT, - awsAccessKeyId: user.awsAccessKeyId ? "****" : null, - awsRegion: user.awsRegion, - awsConfigured: !!(user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion), - setupComplete: !!(user.giteaInstanceUrl && user.giteaPAT && user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion) - } - } - }); -} -async function setupStatusHandler(ctr) { - const count = await import_db.prisma.user.count(); - return (0, import_response.makeResponse)({ ctr, content: { code: 200, data: { needsSetup: count === 0 } } }); -} -async function firstUserHandler(ctr) { - const count = await import_db.prisma.user.count(); - if (count > 0) { - return (0, import_response.makeResponse)({ ctr, content: { code: 403, message: "Setup already completed. Contact an administrator to create your account." } }); - } - let body; - try { - body = await ctr.body(); - } catch { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Invalid body" } }); - } - const { username, password } = body || {}; - if (!username || !password || password.length < 8) { - return (0, import_response.makeResponse)({ ctr, content: { code: 400, message: "Username and password (min 8 chars) required" } }); - } - const hash = await import_bcryptjs.default.hash(password, 12); - const user = await import_db.prisma.user.create({ - data: { username, passwordHash: hash, isAdmin: true, isFounder: true } - }); - const sessionHash = (0, import_crypto.randomBytes)(32).toString("hex"); - await import_db.prisma.session.create({ data: { hash: sessionHash, userId: user.id } }); - ctr.cookies.set( - COOKIE_NAME, - new import_rjweb_server.Cookie(sessionHash, { - httpOnly: true, - expires: new Date(Date.now() + COOKIE_MAX_AGE_MS), - path: "/", - sameSite: "Lax" - }) - ); - log.info({ username }, "First user (founder) created"); - return (0, import_response.makeResponse)({ ctr, content: { code: 201, data: { id: user.id, username: user.username, isAdmin: true, isFounder: true } } }); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - firstUserHandler, - loginHandler, - logoutHandler, - meHandler, - setupStatusHandler -}); -//# sourceMappingURL=auth.js.map diff --git a/backend/dist/routes/auth.js.map b/backend/dist/routes/auth.js.map deleted file mode 100644 index 78020bf8..00000000 --- a/backend/dist/routes/auth.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/routes/auth.ts"], - "sourcesContent": ["import { randomBytes } from \"crypto\";\r\nimport bcrypt from \"bcryptjs\";\r\nimport { Cookie } from \"rjweb-server\";\r\nimport { prisma } from \"../lib/db\";\r\nimport { makeResponse } from \"../lib/response\";\r\nimport { ERROR_MESSAGES } from \"../lib/errors\";\r\nimport { createLogger } from \"../lib/logger\";\r\n\r\nconst log = createLogger(\"AUTH_ROUTE\");\r\nconst COOKIE_NAME = \"pp_session\";\r\nconst COOKIE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\r\n\r\nexport async function loginHandler(ctr: any) {\r\n let body: any;\r\n try {\r\n body = await ctr.body();\r\n } catch {\r\n return makeResponse({ ctr, content: { code: 400, message: \"Invalid body\" } });\r\n }\r\n\r\n const { username, password } = body || {};\r\n if (!username || !password) {\r\n return makeResponse({ ctr, content: { code: 400, message: \"Username and password required\" } });\r\n }\r\n\r\n const user = await prisma.user.findUnique({ where: { username } });\r\n if (!user) {\r\n return makeResponse({ ctr, content: { code: 401, message: \"Invalid credentials\" } });\r\n }\r\n\r\n const valid = await bcrypt.compare(password, user.passwordHash);\r\n if (!valid) {\r\n return makeResponse({ ctr, content: { code: 401, message: \"Invalid credentials\" } });\r\n }\r\n\r\n const sessionHash = randomBytes(32).toString(\"hex\");\r\n await prisma.session.create({ data: { hash: sessionHash, userId: user.id } });\r\n\r\n ctr.cookies.set(\r\n COOKIE_NAME,\r\n new Cookie(sessionHash, {\r\n httpOnly: true,\r\n expires: new Date(Date.now() + COOKIE_MAX_AGE_MS),\r\n path: \"/\",\r\n sameSite: \"Lax\",\r\n }),\r\n );\r\n\r\n return makeResponse({ ctr, content: { code: 200, data: { id: user.id, username: user.username, isAdmin: user.isAdmin } } });\r\n}\r\n\r\nexport async function logoutHandler(ctr: any) {\r\n const auth = ctr.getAuth?.();\r\n if (auth?.success) {\r\n await prisma.session.delete({ where: { id: auth.sessionId } }).catch(() => {});\r\n }\r\n ctr.cookies.set(COOKIE_NAME, new Cookie(\"\", { expires: new Date(0), path: \"/\" }));\r\n return makeResponse({ ctr, content: { code: 200, message: \"Logged out\" } });\r\n}\r\n\r\nexport async function meHandler(ctr: any) {\r\n const auth = ctr.getAuth?.();\r\n if (!auth?.success) {\r\n return makeResponse({ ctr, content: { code: ERROR_MESSAGES.UNAUTHORIZED.code, message: ERROR_MESSAGES.UNAUTHORIZED.message } });\r\n }\r\n\r\n const user = await prisma.user.findUnique({ where: { id: auth.user.id } });\r\n if (!user) return makeResponse({ ctr, content: { code: 404, message: \"User not found\" } });\r\n\r\n return makeResponse({\r\n ctr,\r\n content: {\r\n code: 200,\r\n data: {\r\n id: user.id,\r\n username: user.username,\r\n isAdmin: user.isAdmin,\r\n isFounder: user.isFounder,\r\n giteaUsername: user.giteaUsername,\r\n giteaInstanceUrl: user.giteaInstanceUrl,\r\n giteaPatSet: !!user.giteaPAT,\r\n awsAccessKeyId: user.awsAccessKeyId ? \"****\" : null,\r\n awsRegion: user.awsRegion,\r\n awsConfigured: !!(user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion),\r\n setupComplete: !!(user.giteaInstanceUrl && user.giteaPAT && user.awsAccessKeyId && user.awsSecretAccessKey && user.awsRegion),\r\n },\r\n },\r\n });\r\n}\r\n\r\nexport async function setupStatusHandler(ctr: any) {\r\n const count = await prisma.user.count();\r\n return makeResponse({ ctr, content: { code: 200, data: { needsSetup: count === 0 } } });\r\n}\r\n\r\nexport async function firstUserHandler(ctr: any) {\r\n const count = await prisma.user.count();\r\n if (count > 0) {\r\n return makeResponse({ ctr, content: { code: 403, message: \"Setup already completed. Contact an administrator to create your account.\" } });\r\n }\r\n\r\n let body: any;\r\n try {\r\n body = await ctr.body();\r\n } catch {\r\n return makeResponse({ ctr, content: { code: 400, message: \"Invalid body\" } });\r\n }\r\n\r\n const { username, password } = body || {};\r\n if (!username || !password || password.length < 8) {\r\n return makeResponse({ ctr, content: { code: 400, message: \"Username and password (min 8 chars) required\" } });\r\n }\r\n\r\n const hash = await bcrypt.hash(password, 12);\r\n const user = await prisma.user.create({\r\n data: { username, passwordHash: hash, isAdmin: true, isFounder: true },\r\n });\r\n\r\n const sessionHash = randomBytes(32).toString(\"hex\");\r\n await prisma.session.create({ data: { hash: sessionHash, userId: user.id } });\r\n\r\n ctr.cookies.set(\r\n COOKIE_NAME,\r\n new Cookie(sessionHash, {\r\n httpOnly: true,\r\n expires: new Date(Date.now() + COOKIE_MAX_AGE_MS),\r\n path: \"/\",\r\n sameSite: \"Lax\",\r\n }),\r\n );\r\n\r\n log.info({ username }, \"First user (founder) created\");\r\n return makeResponse({ ctr, content: { code: 201, data: { id: user.id, username: user.username, isAdmin: true, isFounder: true } } });\r\n}\r\n"], - "mappings": "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", - "names": ["bcrypt"] -} diff --git a/backend/dist/routes/webhook.js b/backend/dist/routes/webhook.js deleted file mode 100644 index beaefba7..00000000 --- a/backend/dist/routes/webhook.js +++ /dev/null @@ -1,279 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var webhook_exports = {}; -__export(webhook_exports, { - webhookHandler: () => webhookHandler -}); -module.exports = __toCommonJS(webhook_exports); -var import_crypto = require("crypto"); -var import_db = require("../lib/db"); -var import_logger = require("../lib/logger"); -var import_adminSettings = require("../lib/adminSettings"); -var import_gitea = require("../services/gitea"); -var import_env = require("../lib/env"); -const log = (0, import_logger.createLogger)("WEBHOOK"); -const rateLimitMap = /* @__PURE__ */ new Map(); -function checkRateLimit(userId, limitPerMin) { - const now = Date.now(); - const entry = rateLimitMap.get(userId); - if (!entry || now > entry.resetAt) { - rateLimitMap.set(userId, { count: 1, resetAt: now + 6e4 }); - return true; - } - if (entry.count >= limitPerMin) return false; - entry.count++; - return true; -} -async function webhookHandler(ctr) { - const userId = parseInt(ctr.params.get("userId") || "0", 10); - if (!userId) return ctr.status(400).print({ status: "FAILED", message: "Invalid user ID" }); - const settings = await (0, import_adminSettings.getAdminSettings)(); - if (!checkRateLimit(userId, settings.webhookRateLimitPerMinute)) { - return ctr.status(429).print({ status: "FAILED", message: "Rate limit exceeded" }); - } - const user = await import_db.prisma.user.findUnique({ where: { id: userId } }); - if (!user) return ctr.status(404).print({ status: "FAILED", message: "User not found" }); - const webhookToken = await import_db.prisma.webhookToken.findUnique({ where: { userId } }); - if (!webhookToken) return ctr.status(401).print({ status: "FAILED", message: "No webhook token configured" }); - const signature = ctr.headers.get("x-gitea-signature-256") || ctr.headers.get("x-hub-signature-256") || ""; - const rawBody = await ctr.$body().text(); - const expected = "sha256=" + (0, import_crypto.createHmac)("sha256", webhookToken.token).update(rawBody).digest("hex"); - if (!timingSafeEqual(signature, expected)) { - log.warn({ userId, signature }, "Invalid webhook signature"); - return ctr.status(401).print({ status: "FAILED", message: "Invalid signature" }); - } - let payload; - try { - payload = JSON.parse(rawBody); - } catch { - return ctr.status(400).print({ status: "FAILED", message: "Invalid JSON payload" }); - } - const event = ctr.headers.get("x-gitea-event") || ""; - ctr.status(200).print({ status: "OK" }); - setImmediate(() => handleWebhookAsync(user, event, payload).catch((e) => log.error({ e }, "Webhook processing error"))); -} -async function handleWebhookAsync(user, event, payload) { - if (event === "pull_request") { - await handlePullRequestEvent(user, payload); - } else if (event === "issue_comment") { - await handleIssueCommentEvent(user, payload); - } -} -async function handlePullRequestEvent(user, payload) { - const action = payload.action; - const pr = payload.pull_request; - const repo = payload.repository; - if (!pr || !repo) return; - const owner = repo.owner?.login || repo.full_name?.split("/")[0]; - const repoName = repo.name; - const prNumber = pr.number; - const prTitle = pr.title || `PR #${prNumber}`; - const commitSha = pr.head?.sha || ""; - const cloneUrl = pr.head?.repo?.clone_url || repo.clone_url; - const repoConfig = await import_db.prisma.repoConfig.findFirst({ - where: { repoOwner: owner, repoName, userId: user.id, isEnabled: true } - }); - if (!repoConfig) { - const existing = await import_db.prisma.noConfigComment.findUnique({ - where: { userId_repoOwner_repoName_prNumber: { userId: user.id, repoOwner: owner, repoName, prNumber } } - }); - if (!existing) { - const body = `No previews configured for \`${owner}/${repoName}\`. Configure this repo in [PR Previews](${import_env.env.PP_BASE_URL}).`; - try { - await (0, import_gitea.postComment)(user, owner, repoName, prNumber, body); - await import_db.prisma.noConfigComment.create({ data: { userId: user.id, repoOwner: owner, repoName, prNumber } }); - } catch { - } - } - return; - } - if (repoConfig.denyList.includes(pr.user?.login || "")) return; - if (action === "opened" || action === "reopened") { - let preview = await import_db.prisma.preview.findFirst({ - where: { repoConfigId: repoConfig.id, prNumber }, - orderBy: { createdAt: "desc" } - }); - if (preview && preview.status === "IGNORED") return; - if (!preview || preview.status === "STOPPED") { - preview = await import_db.prisma.preview.create({ - data: { - repoConfigId: repoConfig.id, - prNumber, - prTitle, - commitSha, - status: "PROVISIONING", - port: repoConfig.port - } - }); - await import_db.prisma.job.create({ - data: { - previewId: preview.id, - type: "DEPLOY", - status: "PENDING", - payload: { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy: true } - } - }); - } - } else if (action === "synchronize") { - const preview = await import_db.prisma.preview.findFirst({ - where: { repoConfigId: repoConfig.id, prNumber }, - orderBy: { createdAt: "desc" } - }); - if (!preview || preview.status === "IGNORED") return; - await import_db.prisma.preview.update({ where: { id: preview.id }, data: { lastActivityAt: /* @__PURE__ */ new Date() } }); - await import_db.prisma.job.create({ - data: { - previewId: preview.id, - type: "DEPLOY", - status: "PENDING", - payload: { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy: preview.status === "STOPPED" } - } - }); - } else if (action === "closed") { - const preview = await import_db.prisma.preview.findFirst({ - where: { repoConfigId: repoConfig.id, prNumber }, - orderBy: { createdAt: "desc" } - }); - if (preview && preview.status !== "STOPPED" && preview.status !== "IGNORED") { - await import_db.prisma.job.create({ - data: { - previewId: preview.id, - type: "STOP", - status: "PENDING", - payload: { reason: "PR closed" } - } - }); - } - } -} -async function handleIssueCommentEvent(user, payload) { - const action = payload.action; - if (action !== "created") return; - const comment = payload.comment; - const issue = payload.issue; - const repo = payload.repository; - if (!comment || !issue || !repo || !issue.pull_request) return; - const body = comment.body || ""; - if (!body.trimStart().startsWith("/pp ")) return; - const owner = repo.owner?.login || repo.full_name?.split("/")[0]; - const repoName = repo.name; - const prNumber = issue.number; - if (user.giteaUsername && comment.user?.login === user.giteaUsername) return; - const repoConfig = await import_db.prisma.repoConfig.findFirst({ - where: { repoOwner: owner, repoName, userId: user.id, isEnabled: true } - }); - if (!repoConfig) return; - const commenter = comment.user?.login || ""; - const prAuthor = issue.user?.login || ""; - const isAllowed = commenter === prAuthor || await isRepoAdmin(user, owner, repoName, commenter); - if (!isAllowed) return; - await import_db.prisma.preview.updateMany({ - where: { - repoConfigId: repoConfig.id, - prNumber, - status: { in: ["RUNNING", "BUILDING", "FAILED", "PROVISIONING"] } - }, - data: { lastActivityAt: /* @__PURE__ */ new Date() } - }); - const commandLine = body.trimStart().split("\n")[0].trim(); - const command = commandLine.replace("/pp ", "").trim(); - const preview = await import_db.prisma.preview.findFirst({ - where: { repoConfigId: repoConfig.id, prNumber }, - orderBy: { createdAt: "desc" } - }); - const cloneUrl = repo.clone_url; - if (command === "rebuild") { - if (!preview || preview.status !== "RUNNING" && preview.status !== "FAILED") return; - await import_db.prisma.job.create({ - data: { - previewId: preview.id, - type: "DEPLOY", - status: "PENDING", - payload: { commitSha: preview.commitSha, prNumber, prTitle: preview.prTitle, cloneUrl, isFirstDeploy: false } - } - }); - } else if (command === "stop") { - if (!preview || preview.status === "STOPPED") return; - await import_db.prisma.job.create({ - data: { previewId: preview.id, type: "STOP", status: "PENDING", payload: { reason: "Manual stop" } } - }); - } else if (command === "start") { - if (!preview) { - const newPreview = await import_db.prisma.preview.create({ - data: { repoConfigId: repoConfig.id, prNumber, prTitle: issue.title, commitSha: "", status: "PROVISIONING", port: repoConfig.port } - }); - await import_db.prisma.job.create({ - data: { previewId: newPreview.id, type: "DEPLOY", status: "PENDING", payload: { commitSha: "", prNumber, prTitle: issue.title, cloneUrl, isFirstDeploy: true } } - }); - } else if (preview.status === "STOPPED" || preview.status === "IGNORED") { - await import_db.prisma.preview.update({ where: { id: preview.id }, data: { status: "PROVISIONING" } }); - await import_db.prisma.job.create({ - data: { previewId: preview.id, type: "DEPLOY", status: "PENDING", payload: { commitSha: preview.commitSha, prNumber, prTitle: preview.prTitle, cloneUrl, isFirstDeploy: true } } - }); - } - } else if (command === "logs") { - if (!preview) return; - const lastLines = (preview.logs || "").split("\n").slice(-50).join("\n"); - const logBody = `**PP Logs** (last 50 lines) -\`\`\` -${lastLines} -\`\`\``; - await (0, import_gitea.postComment)(user, owner, repoName, prNumber, logBody); - } else if (command === "ignore") { - if (!preview) { - await import_db.prisma.preview.create({ - data: { repoConfigId: repoConfig.id, prNumber, prTitle: issue.title, commitSha: "", status: "IGNORED", port: repoConfig.port } - }); - } else { - await import_db.prisma.preview.update({ where: { id: preview.id }, data: { status: "IGNORED" } }); - } - } -} -async function isRepoAdmin(user, owner, repo, username) { - try { - const { getRepoCollaboratorPermission } = await import("../services/gitea"); - const permission = await getRepoCollaboratorPermission(user, owner, repo, username); - return permission === "owner" || permission === "admin"; - } catch { - return false; - } -} -function timingSafeEqual(a, b) { - if (a.length !== b.length) return false; - let diff = 0; - for (let i = 0; i < a.length; i++) { - diff |= a.charCodeAt(i) ^ b.charCodeAt(i); - } - return diff === 0; -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - webhookHandler -}); -//# sourceMappingURL=webhook.js.map diff --git a/backend/dist/routes/webhook.js.map b/backend/dist/routes/webhook.js.map deleted file mode 100644 index eefd33aa..00000000 --- a/backend/dist/routes/webhook.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/routes/webhook.ts"], - "sourcesContent": ["import { createHmac } from \"crypto\";\nimport { prisma } from \"../lib/db\";\nimport { createLogger } from \"../lib/logger\";\nimport { getAdminSettings } from \"../lib/adminSettings\";\nimport { buildPrCommentBody, postComment } from \"../services/gitea\";\nimport { env } from \"../lib/env\";\n\nconst log = createLogger(\"WEBHOOK\");\n\nconst rateLimitMap = new Map();\n\nfunction checkRateLimit(userId: number, limitPerMin: number): boolean {\n const now = Date.now();\n const entry = rateLimitMap.get(userId);\n if (!entry || now > entry.resetAt) {\n rateLimitMap.set(userId, { count: 1, resetAt: now + 60_000 });\n return true;\n }\n if (entry.count >= limitPerMin) return false;\n entry.count++;\n return true;\n}\n\nexport async function webhookHandler(ctr: any) {\n const userId = parseInt(ctr.params.get(\"userId\") || \"0\", 10);\n if (!userId) return ctr.status(400).print({ status: \"FAILED\", message: \"Invalid user ID\" });\n\n const settings = await getAdminSettings();\n\n if (!checkRateLimit(userId, settings.webhookRateLimitPerMinute)) {\n return ctr.status(429).print({ status: \"FAILED\", message: \"Rate limit exceeded\" });\n }\n\n const user = await prisma.user.findUnique({ where: { id: userId } });\n if (!user) return ctr.status(404).print({ status: \"FAILED\", message: \"User not found\" });\n\n const webhookToken = await prisma.webhookToken.findUnique({ where: { userId } });\n if (!webhookToken) return ctr.status(401).print({ status: \"FAILED\", message: \"No webhook token configured\" });\n\n const signature = ctr.headers.get(\"x-gitea-signature-256\") || ctr.headers.get(\"x-hub-signature-256\") || \"\";\n const rawBody = await ctr.$body().text();\n\n const expected = \"sha256=\" + createHmac(\"sha256\", webhookToken.token).update(rawBody).digest(\"hex\");\n if (!timingSafeEqual(signature, expected)) {\n log.warn({ userId, signature }, \"Invalid webhook signature\");\n return ctr.status(401).print({ status: \"FAILED\", message: \"Invalid signature\" });\n }\n\n let payload: any;\n try {\n payload = JSON.parse(rawBody);\n } catch {\n return ctr.status(400).print({ status: \"FAILED\", message: \"Invalid JSON payload\" });\n }\n\n const event = ctr.headers.get(\"x-gitea-event\") || \"\";\n\n ctr.status(200).print({ status: \"OK\" });\n\n setImmediate(() => handleWebhookAsync(user, event, payload).catch(e => log.error({ e }, \"Webhook processing error\")));\n}\n\nasync function handleWebhookAsync(user: any, event: string, payload: any) {\n if (event === \"pull_request\") {\n await handlePullRequestEvent(user, payload);\n } else if (event === \"issue_comment\") {\n await handleIssueCommentEvent(user, payload);\n }\n}\n\nasync function handlePullRequestEvent(user: any, payload: any) {\n const action = payload.action;\n const pr = payload.pull_request;\n const repo = payload.repository;\n if (!pr || !repo) return;\n\n const owner = repo.owner?.login || repo.full_name?.split(\"/\")[0];\n const repoName = repo.name;\n const prNumber = pr.number;\n const prTitle = pr.title || `PR #${prNumber}`;\n const commitSha = pr.head?.sha || \"\";\n const cloneUrl = pr.head?.repo?.clone_url || repo.clone_url;\n\n const repoConfig = await prisma.repoConfig.findFirst({\n where: { repoOwner: owner, repoName, userId: user.id, isEnabled: true },\n });\n\n if (!repoConfig) {\n const existing = await prisma.noConfigComment.findUnique({\n where: { userId_repoOwner_repoName_prNumber: { userId: user.id, repoOwner: owner, repoName, prNumber } },\n });\n if (!existing) {\n const body = `No previews configured for \\`${owner}/${repoName}\\`. Configure this repo in [PR Previews](${env.PP_BASE_URL}).`;\n try {\n await postComment(user, owner, repoName, prNumber, body);\n await prisma.noConfigComment.create({ data: { userId: user.id, repoOwner: owner, repoName, prNumber } });\n } catch {}\n }\n return;\n }\n\n if (repoConfig.denyList.includes(pr.user?.login || \"\")) return;\n\n if (action === \"opened\" || action === \"reopened\") {\n let preview = await prisma.preview.findFirst({\n where: { repoConfigId: repoConfig.id, prNumber },\n orderBy: { createdAt: \"desc\" },\n });\n\n if (preview && preview.status === \"IGNORED\") return;\n\n if (!preview || preview.status === \"STOPPED\") {\n preview = await prisma.preview.create({\n data: {\n repoConfigId: repoConfig.id,\n prNumber,\n prTitle,\n commitSha,\n status: \"PROVISIONING\",\n port: repoConfig.port,\n },\n });\n\n await prisma.job.create({\n data: {\n previewId: preview.id,\n type: \"DEPLOY\",\n status: \"PENDING\",\n payload: { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy: true },\n },\n });\n }\n } else if (action === \"synchronize\") {\n const preview = await prisma.preview.findFirst({\n where: { repoConfigId: repoConfig.id, prNumber },\n orderBy: { createdAt: \"desc\" },\n });\n\n if (!preview || preview.status === \"IGNORED\") return;\n\n await prisma.preview.update({ where: { id: preview.id }, data: { lastActivityAt: new Date() } });\n\n await prisma.job.create({\n data: {\n previewId: preview.id,\n type: \"DEPLOY\",\n status: \"PENDING\",\n payload: { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy: preview.status === \"STOPPED\" },\n },\n });\n } else if (action === \"closed\") {\n const preview = await prisma.preview.findFirst({\n where: { repoConfigId: repoConfig.id, prNumber },\n orderBy: { createdAt: \"desc\" },\n });\n\n if (preview && preview.status !== \"STOPPED\" && preview.status !== \"IGNORED\") {\n await prisma.job.create({\n data: {\n previewId: preview.id,\n type: \"STOP\",\n status: \"PENDING\",\n payload: { reason: \"PR closed\" },\n },\n });\n }\n }\n}\n\nasync function handleIssueCommentEvent(user: any, payload: any) {\n const action = payload.action;\n if (action !== \"created\") return;\n\n const comment = payload.comment;\n const issue = payload.issue;\n const repo = payload.repository;\n if (!comment || !issue || !repo || !issue.pull_request) return;\n\n const body = comment.body || \"\";\n if (!body.trimStart().startsWith(\"/pp \")) return;\n\n const owner = repo.owner?.login || repo.full_name?.split(\"/\")[0];\n const repoName = repo.name;\n const prNumber = issue.number;\n\n if (user.giteaUsername && comment.user?.login === user.giteaUsername) return;\n\n const repoConfig = await prisma.repoConfig.findFirst({\n where: { repoOwner: owner, repoName, userId: user.id, isEnabled: true },\n });\n if (!repoConfig) return;\n\n const commenter = comment.user?.login || \"\";\n const prAuthor = issue.user?.login || \"\";\n const isAllowed = commenter === prAuthor || (await isRepoAdmin(user, owner, repoName, commenter));\n if (!isAllowed) return;\n\n await prisma.preview.updateMany({\n where: {\n repoConfigId: repoConfig.id,\n prNumber,\n status: { in: [\"RUNNING\", \"BUILDING\", \"FAILED\", \"PROVISIONING\"] },\n },\n data: { lastActivityAt: new Date() },\n });\n\n const commandLine = body.trimStart().split(\"\\n\")[0].trim();\n const command = commandLine.replace(\"/pp \", \"\").trim();\n\n const preview = await prisma.preview.findFirst({\n where: { repoConfigId: repoConfig.id, prNumber },\n orderBy: { createdAt: \"desc\" },\n });\n\n const cloneUrl = repo.clone_url;\n\n if (command === \"rebuild\") {\n if (!preview || (preview.status !== \"RUNNING\" && preview.status !== \"FAILED\")) return;\n await prisma.job.create({\n data: {\n previewId: preview.id,\n type: \"DEPLOY\",\n status: \"PENDING\",\n payload: { commitSha: preview.commitSha, prNumber, prTitle: preview.prTitle, cloneUrl, isFirstDeploy: false },\n },\n });\n } else if (command === \"stop\") {\n if (!preview || preview.status === \"STOPPED\") return;\n await prisma.job.create({\n data: { previewId: preview.id, type: \"STOP\", status: \"PENDING\", payload: { reason: \"Manual stop\" } },\n });\n } else if (command === \"start\") {\n if (!preview) {\n const newPreview = await prisma.preview.create({\n data: { repoConfigId: repoConfig.id, prNumber, prTitle: issue.title, commitSha: \"\", status: \"PROVISIONING\", port: repoConfig.port },\n });\n await prisma.job.create({\n data: { previewId: newPreview.id, type: \"DEPLOY\", status: \"PENDING\", payload: { commitSha: \"\", prNumber, prTitle: issue.title, cloneUrl, isFirstDeploy: true } },\n });\n } else if (preview.status === \"STOPPED\" || preview.status === \"IGNORED\") {\n await prisma.preview.update({ where: { id: preview.id }, data: { status: \"PROVISIONING\" } });\n await prisma.job.create({\n data: { previewId: preview.id, type: \"DEPLOY\", status: \"PENDING\", payload: { commitSha: preview.commitSha, prNumber, prTitle: preview.prTitle, cloneUrl, isFirstDeploy: true } },\n });\n }\n } else if (command === \"logs\") {\n if (!preview) return;\n const lastLines = (preview.logs || \"\").split(\"\\n\").slice(-50).join(\"\\n\");\n const logBody = `**PP Logs** (last 50 lines)\\n\\`\\`\\`\\n${lastLines}\\n\\`\\`\\``;\n await postComment(user, owner, repoName, prNumber, logBody);\n } else if (command === \"ignore\") {\n if (!preview) {\n await prisma.preview.create({\n data: { repoConfigId: repoConfig.id, prNumber, prTitle: issue.title, commitSha: \"\", status: \"IGNORED\", port: repoConfig.port },\n });\n } else {\n await prisma.preview.update({ where: { id: preview.id }, data: { status: \"IGNORED\" } });\n }\n }\n}\n\nasync function isRepoAdmin(user: any, owner: string, repo: string, username: string): Promise {\n try {\n const { getRepoCollaboratorPermission } = await import(\"../services/gitea\");\n const permission = await getRepoCollaboratorPermission(user, owner, repo, username);\n return permission === \"owner\" || permission === \"admin\";\n } catch {\n return false;\n }\n}\n\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) {\n diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return diff === 0;\n}\n"], - "mappings": "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", - "names": [] -} diff --git a/backend/dist/services/deploy.js b/backend/dist/services/deploy.js deleted file mode 100644 index 0344d3c5..00000000 --- a/backend/dist/services/deploy.js +++ /dev/null @@ -1,440 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var deploy_exports = {}; -__export(deploy_exports, { - abortJobForPreview: () => abortJobForPreview, - appendLog: () => appendLog, - runDeploy: () => runDeploy, - signalAbort: () => signalAbort, - stopPreview: () => stopPreview, - subscribeToLogs: () => subscribeToLogs -}); -module.exports = __toCommonJS(deploy_exports); -var import_db = require("../lib/db"); -var import_logger = require("../lib/logger"); -var import_encryption = require("../lib/encryption"); -var import_adminSettings = require("../lib/adminSettings"); -var import_env = require("../lib/env"); -var import_ec2 = require("./ec2"); -var import_ssh = require("./ssh"); -var import_gitea = require("./gitea"); -const log = (0, import_logger.createLogger)("DEPLOY"); -const activeSshSessions = /* @__PURE__ */ new Map(); -function abortJobForPreview(previewId) { - const session = activeSshSessions.get(previewId); - if (session) { - session.abort(); - activeSshSessions.delete(previewId); - } -} -async function appendLog(previewId, text) { - const settings = await (0, import_adminSettings.getAdminSettings)(); - const preview = await import_db.prisma.preview.findUnique({ where: { id: previewId } }); - if (!preview) return; - let logs = (preview.logs || "") + text; - if (Buffer.byteLength(logs, "utf8") > settings.logSizeLimitBytes) { - const marker = "--- logs truncated ---\n"; - while (Buffer.byteLength(logs, "utf8") > settings.logSizeLimitBytes) { - const nl = logs.indexOf("\n"); - if (nl === -1) break; - logs = logs.slice(nl + 1); - } - logs = marker + logs; - } - await import_db.prisma.preview.update({ where: { id: previewId }, data: { logs } }); - broadcastLogUpdate(previewId, text); -} -const logSubscribers = /* @__PURE__ */ new Map(); -function subscribeToLogs(previewId, cb) { - if (!logSubscribers.has(previewId)) logSubscribers.set(previewId, /* @__PURE__ */ new Set()); - logSubscribers.get(previewId).add(cb); - return () => logSubscribers.get(previewId)?.delete(cb); -} -function broadcastLogUpdate(previewId, text) { - logSubscribers.get(previewId)?.forEach((cb) => cb(text)); -} -async function updateStatus(previewId, status, extra = {}) { - await import_db.prisma.preview.update({ where: { id: previewId }, data: { status, ...extra } }); -} -async function updateGiteaComment(user, preview, repoConfig, statusLine, lastLogLines) { - const body = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber: preview.prNumber, - status: statusLine, - commitSha: preview.commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL, - lastLogLines, - instanceIp: preview.instanceIp ?? void 0, - port: preview.port - }); - if (preview.giteaCommentId) { - try { - await (0, import_gitea.updateComment)(user, repoConfig.repoOwner, repoConfig.repoName, preview.giteaCommentId, body); - } catch (e) { - log.warn({ e }, "Failed to update Gitea comment"); - } - } -} -async function runDeploy(jobId) { - const job = await import_db.prisma.job.findUnique({ where: { id: jobId }, include: { preview: { include: { repoConfig: { include: { user: true } } } } } }); - if (!job || !job.preview) { - log.error({ jobId }, "Job or preview not found"); - return; - } - await import_db.prisma.job.update({ where: { id: jobId }, data: { status: "RUNNING", startedAt: /* @__PURE__ */ new Date() } }); - const preview = job.preview; - const repoConfig = preview.repoConfig; - const user = preview.repoConfig.user; - const payload = job.payload; - const { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy } = payload; - try { - if (isFirstDeploy) { - await firstDeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle, cloneUrl); - } else { - await redeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle); - } - await import_db.prisma.job.update({ where: { id: jobId }, data: { status: "DONE", finishedAt: /* @__PURE__ */ new Date() } }); - } catch (e) { - if (e.message === "ABORTED") { - log.info({ jobId, previewId: preview.id }, "Job aborted"); - await import_db.prisma.job.update({ where: { id: jobId }, data: { status: "FAILED", error: "Aborted by newer deploy", finishedAt: /* @__PURE__ */ new Date() } }); - return; - } - log.error({ e, jobId, previewId: preview.id }, "Deploy failed"); - await import_db.prisma.job.update({ where: { id: jobId }, data: { status: "FAILED", error: e.message, finishedAt: /* @__PURE__ */ new Date() } }); - const freshPreview = await import_db.prisma.preview.findUnique({ where: { id: preview.id } }); - if (!freshPreview) return; - const lastLines = (freshPreview.logs || "").split("\n").slice(-10).join("\n"); - await updateStatus(preview.id, "FAILED"); - const failBody = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber: freshPreview.prNumber, - status: `\u{1F534} Failed \u2014 last log lines: -\`\`\` -${lastLines} -\`\`\``, - commitSha: freshPreview.commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }); - if (freshPreview.giteaCommentId) { - try { - await (0, import_gitea.updateComment)(user, repoConfig.repoOwner, repoConfig.repoName, freshPreview.giteaCommentId, failBody); - } catch { - } - } - } -} -async function firstDeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle, cloneUrl) { - const settings = await (0, import_adminSettings.getAdminSettings)(); - const ec2 = (0, import_ec2.makeEc2Client)(user); - const previewId = preview.id; - const activeCount = await import_db.prisma.preview.count({ - where: { - repoConfig: { userId: user.id }, - status: { in: ["PROVISIONING", "BUILDING", "RUNNING"] }, - id: { not: previewId } - } - }); - if (activeCount >= settings.maxConcurrentInstancesPerUser) { - const body = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: `\u{1F534} Cannot provision preview \u2014 concurrent instance limit (${settings.maxConcurrentInstancesPerUser}) reached.`, - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }); - const commentId2 = await (0, import_gitea.postComment)(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, body); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: commentId2 } }); - throw new Error("Concurrent instance limit reached"); - } - await updateStatus(previewId, "PROVISIONING", { commitSha, prNumber, prTitle }); - const commentBody = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: "\u{1F7E1} Provisioning EC2 instance...", - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }); - let commentId = await (0, import_gitea.postComment)(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, commentBody); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: commentId } }); - checkAbort(previewId); - const keyName = `pp-preview-${previewId}`; - const { privateKey } = await (0, import_ec2.generateAndImportKeyPair)(ec2, keyName); - const encPrivateKey = (0, import_encryption.encrypt)(privateKey); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { sshPrivateKey: encPrivateKey, sshKeyName: keyName } }); - checkAbort(previewId); - const sgName = `pp-preview-${previewId}`; - const securityGroupId = await (0, import_ec2.createPreviewSecurityGroup)(ec2, sgName, repoConfig.port); - checkAbort(previewId); - const instanceId = await (0, import_ec2.launchInstance)({ - ec2, - region: user.awsRegion, - instanceType: repoConfig.instanceType, - keyName, - securityGroupId, - tags: { - "pp:managed": "true", - "pp:userId": String(user.id), - "pp:repo": `${repoConfig.repoOwner}/${repoConfig.repoName}`, - "pp:prNumber": String(prNumber), - "pp:previewId": String(previewId) - } - }); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { instanceId } }); - await appendLog(previewId, `[PP] EC2 instance ${instanceId} launched. Waiting for it to be running... -`); - checkAbort(previewId); - const instanceIp = await (0, import_ec2.waitForInstanceRunning)(ec2, instanceId); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { instanceIp, port: repoConfig.port } }); - await (0, import_gitea.updateComment)( - user, - repoConfig.repoOwner, - repoConfig.repoName, - commentId, - (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: `\u{1F7E1} Building... (EC2 ready at ${instanceIp})`, - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }) - ); - await appendLog(previewId, `[PP] Instance running at ${instanceIp}. Waiting for SSH... -`); - checkAbort(previewId); - const sshSession = await (0, import_ssh.connectSsh)(instanceIp, privateKey, 3e5); - activeSshSessions.set(previewId, sshSession); - try { - if (repoConfig.aptPackages.length > 0) { - await runSshStep(previewId, sshSession, `sudo apt-get install -y ${repoConfig.aptPackages.join(" ")}`); - } - const giteaPat = user.giteaPAT ? (0, import_encryption.decrypt)(user.giteaPAT) : ""; - const authCloneUrl = cloneUrl.replace("https://", `https://${user.giteaUsername}:${giteaPat}@`); - await runSshStep(previewId, sshSession, `git clone ${authCloneUrl} /opt/app`); - await runSshStep(previewId, sshSession, `cd /opt/app && git fetch origin pull/${prNumber}/head:pp-pr && git checkout pp-pr`); - await setupAndBuild(previewId, sshSession, repoConfig, preview, commitSha, true); - await updateStatus(previewId, "RUNNING", { commitSha, instanceIp, port: repoConfig.port, lastActivityAt: /* @__PURE__ */ new Date() }); - const freshPreview = await import_db.prisma.preview.findUnique({ where: { id: previewId } }); - await (0, import_gitea.updateComment)( - user, - repoConfig.repoOwner, - repoConfig.repoName, - commentId, - (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: `\u{1F7E2} Live at http://${instanceIp}:${repoConfig.port}`, - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }) - ); - } finally { - sshSession.close(); - activeSshSessions.delete(previewId); - } -} -async function redeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle) { - const previewId = preview.id; - const instanceIp = preview.instanceIp; - const privateKey = (0, import_encryption.decrypt)(preview.sshPrivateKey); - const sshSession = await (0, import_ssh.connectSsh)(instanceIp, privateKey, 3e4); - activeSshSessions.set(previewId, sshSession); - await appendLog(previewId, ` ---- Redeploy: ${commitSha} --- -`); - const freshPreview = await import_db.prisma.preview.findUnique({ where: { id: previewId } }); - const commentBody = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: `\u{1F7E1} Building... (EC2 at ${instanceIp})`, - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }); - const newCommentId = await (0, import_gitea.postComment)(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, commentBody); - await import_db.prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: newCommentId, commitSha } }); - try { - if (repoConfig.useDockerCompose) { - const composePath = repoConfig.composeFilePath || "docker-compose.yml"; - await runSshStep(previewId, sshSession, `cd /opt/app && docker compose -f ${composePath} down 2>&1 || true`); - } else if (freshPreview?.pid) { - await runSshStep(previewId, sshSession, `kill ${freshPreview.pid} 2>/dev/null || true; sleep 5; kill -9 ${freshPreview.pid} 2>/dev/null || true`); - } - await runSshStep(previewId, sshSession, `cd /opt/app && git fetch origin pull/${prNumber}/head:pp-pr && git checkout pp-pr && git reset --hard FETCH_HEAD`); - await updateStatus(previewId, "BUILDING"); - await setupAndBuild(previewId, sshSession, repoConfig, preview, commitSha, false); - await updateStatus(previewId, "RUNNING", { commitSha, lastActivityAt: /* @__PURE__ */ new Date() }); - await (0, import_gitea.updateComment)( - user, - repoConfig.repoOwner, - repoConfig.repoName, - newCommentId, - (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber, - status: `\u{1F7E2} Live at http://${instanceIp}:${repoConfig.port}`, - commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }) - ); - } finally { - sshSession.close(); - activeSshSessions.delete(previewId); - } -} -async function setupAndBuild(previewId, sshSession, repoConfig, preview, commitSha, isFirstProvision) { - await detectAndUseNode(previewId, sshSession); - const envVars = repoConfig.envVars; - const envContent = Object.entries(envVars).map(([k, v]) => `${k}=${v}`).join("\n"); - await runSshStep(previewId, sshSession, `cat > /opt/app/.env << 'PPEOF' -${envContent} -PPEOF`); - if (isFirstProvision) { - for (const cmd of repoConfig.setupCommands) { - await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`); - } - } - await updateStatus(previewId, "BUILDING"); - if (repoConfig.useDockerCompose) { - const composePath = repoConfig.composeFilePath || "docker-compose.yml"; - await runSshStep(previewId, sshSession, `cd /opt/app && docker compose -f ${composePath} up -d --build --force-recreate 2>&1`); - } else { - for (const cmd of repoConfig.buildCommands) { - await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`); - } - for (const cmd of repoConfig.postBuildCommands) { - await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`); - } - if (repoConfig.runCommand) { - const res = await runSshStep( - previewId, - sshSession, - `cd /opt/app && nohup ${repoConfig.runCommand} > /opt/app/pp.log 2>&1 & echo $!` - ); - const pid = parseInt(res.stdout.trim(), 10); - if (!isNaN(pid)) { - await import_db.prisma.preview.update({ where: { id: previewId }, data: { pid } }); - } - } - } -} -async function detectAndUseNode(previewId, sshSession) { - const nvmSource = `export NVM_DIR="/root/.nvm" && source "$NVM_DIR/nvm.sh"`; - const res = await runSshStep(previewId, sshSession, `${nvmSource} && [ -f /opt/app/.nvmrc ] && nvm install && nvm use || nvm use default 2>&1`, false); -} -async function runSshStep(previewId, sshSession, command, throwOnFail = true) { - checkAbortSession(sshSession); - await appendLog(previewId, `$ ${command} -`); - const res = await sshSession.exec(command); - if (res.stdout) await appendLog(previewId, res.stdout); - if (res.stderr) await appendLog(previewId, res.stderr); - if (throwOnFail && res.code !== 0) { - throw new Error(`Command failed with exit code ${res.code}: ${command}`); - } - return res; -} -function checkAbortSession(session) { - if (session.aborted) throw new Error("ABORTED"); -} -const abortSignals = /* @__PURE__ */ new Set(); -function signalAbort(previewId) { - abortSignals.add(previewId); - abortJobForPreview(previewId); -} -function checkAbort(previewId) { - if (abortSignals.has(previewId)) { - abortSignals.delete(previewId); - throw new Error("ABORTED"); - } -} -async function stopPreview(previewId, reason = "STOPPED") { - const preview = await import_db.prisma.preview.findUnique({ - where: { id: previewId }, - include: { repoConfig: { include: { user: true } } } - }); - if (!preview) return; - const user = preview.repoConfig.user; - const repoConfig = preview.repoConfig; - if (preview.instanceId) { - const ec2 = (0, import_ec2.makeEc2Client)(user); - try { - await (0, import_ec2.deleteKeyPairAws)(ec2, `pp-preview-${previewId}`); - } catch { - } - try { - await (0, import_ec2.deleteSecurityGroupAws)(ec2, `pp-preview-${previewId}`); - } catch { - } - try { - await (0, import_ec2.terminateInstance)(ec2, preview.instanceId); - } catch { - } - } - await import_db.prisma.preview.update({ - where: { id: previewId }, - data: { - status: reason, - stoppedAt: /* @__PURE__ */ new Date(), - sshPrivateKey: null, - sshKeyName: null, - instanceId: null - } - }); - const stoppedBody = (0, import_gitea.buildPrCommentBody)({ - owner: repoConfig.repoOwner, - repo: repoConfig.repoName, - prNumber: preview.prNumber, - status: "\u26AB Stopped (inactivity timeout / PR closed / manual stop)", - commitSha: preview.commitSha, - updatedAt: /* @__PURE__ */ new Date(), - ppBaseUrl: import_env.env.PP_BASE_URL - }); - if (preview.giteaCommentId) { - try { - await (0, import_gitea.updateComment)(user, repoConfig.repoOwner, repoConfig.repoName, preview.giteaCommentId, stoppedBody); - } catch { - } - } -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - abortJobForPreview, - appendLog, - runDeploy, - signalAbort, - stopPreview, - subscribeToLogs -}); -//# sourceMappingURL=deploy.js.map diff --git a/backend/dist/services/deploy.js.map b/backend/dist/services/deploy.js.map deleted file mode 100644 index 8afa4cb7..00000000 --- a/backend/dist/services/deploy.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/services/deploy.ts"], - "sourcesContent": ["import { prisma } from \"../lib/db\";\nimport { createLogger } from \"../lib/logger\";\nimport { decrypt, encrypt } from \"../lib/encryption\";\nimport { getAdminSettings } from \"../lib/adminSettings\";\nimport { env } from \"../lib/env\";\nimport {\n makeEc2Client,\n generateAndImportKeyPair,\n createPreviewSecurityGroup,\n launchInstance,\n waitForInstanceRunning,\n terminateInstance,\n deleteKeyPairAws,\n deleteSecurityGroupAws,\n} from \"./ec2\";\nimport { connectSsh, type SshSession } from \"./ssh\";\nimport {\n buildPrCommentBody,\n postComment,\n updateComment,\n} from \"./gitea\";\nimport type { Preview, RepoConfig, User } from \"@prisma/client\";\n\nconst log = createLogger(\"DEPLOY\");\n\nconst activeSshSessions = new Map();\n\nexport function abortJobForPreview(previewId: number) {\n const session = activeSshSessions.get(previewId);\n if (session) {\n session.abort();\n activeSshSessions.delete(previewId);\n }\n}\n\nexport async function appendLog(previewId: number, text: string) {\n const settings = await getAdminSettings();\n const preview = await prisma.preview.findUnique({ where: { id: previewId } });\n if (!preview) return;\n\n let logs = (preview.logs || \"\") + text;\n if (Buffer.byteLength(logs, \"utf8\") > settings.logSizeLimitBytes) {\n const marker = \"--- logs truncated ---\\n\";\n while (Buffer.byteLength(logs, \"utf8\") > settings.logSizeLimitBytes) {\n const nl = logs.indexOf(\"\\n\");\n if (nl === -1) break;\n logs = logs.slice(nl + 1);\n }\n logs = marker + logs;\n }\n\n await prisma.preview.update({ where: { id: previewId }, data: { logs } });\n\n broadcastLogUpdate(previewId, text);\n}\n\nconst logSubscribers = new Map void>>();\n\nexport function subscribeToLogs(previewId: number, cb: (text: string) => void): () => void {\n if (!logSubscribers.has(previewId)) logSubscribers.set(previewId, new Set());\n logSubscribers.get(previewId)!.add(cb);\n return () => logSubscribers.get(previewId)?.delete(cb);\n}\n\nfunction broadcastLogUpdate(previewId: number, text: string) {\n logSubscribers.get(previewId)?.forEach(cb => cb(text));\n}\n\nasync function updateStatus(previewId: number, status: Preview[\"status\"], extra: Partial = {}) {\n await prisma.preview.update({ where: { id: previewId }, data: { status, ...extra } });\n}\n\nasync function updateGiteaComment(user: User, preview: Preview, repoConfig: RepoConfig, statusLine: string, lastLogLines?: string) {\n const body = buildPrCommentBody({\n owner: repoConfig.repoOwner,\n repo: repoConfig.repoName,\n prNumber: preview.prNumber,\n status: statusLine,\n commitSha: preview.commitSha,\n updatedAt: new Date(),\n ppBaseUrl: env.PP_BASE_URL,\n lastLogLines,\n instanceIp: preview.instanceIp ?? undefined,\n port: preview.port,\n });\n\n if (preview.giteaCommentId) {\n try {\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, preview.giteaCommentId, body);\n } catch (e) {\n log.warn({ e }, \"Failed to update Gitea comment\");\n }\n }\n}\n\nexport async function runDeploy(jobId: number) {\n const job = await prisma.job.findUnique({ where: { id: jobId }, include: { preview: { include: { repoConfig: { include: { user: true } } } } } });\n if (!job || !job.preview) {\n log.error({ jobId }, \"Job or preview not found\");\n return;\n }\n\n await prisma.job.update({ where: { id: jobId }, data: { status: \"RUNNING\", startedAt: new Date() } });\n\n const preview = job.preview as any;\n const repoConfig: RepoConfig = preview.repoConfig;\n const user: User = (preview.repoConfig as any).user;\n\n const payload = job.payload as any;\n const { commitSha, prNumber, prTitle, cloneUrl, isFirstDeploy } = payload;\n\n try {\n if (isFirstDeploy) {\n await firstDeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle, cloneUrl);\n } else {\n await redeploy(jobId, preview, repoConfig, user, commitSha, prNumber, prTitle);\n }\n\n await prisma.job.update({ where: { id: jobId }, data: { status: \"DONE\", finishedAt: new Date() } });\n } catch (e: any) {\n if (e.message === \"ABORTED\") {\n log.info({ jobId, previewId: preview.id }, \"Job aborted\");\n await prisma.job.update({ where: { id: jobId }, data: { status: \"FAILED\", error: \"Aborted by newer deploy\", finishedAt: new Date() } });\n return;\n }\n log.error({ e, jobId, previewId: preview.id }, \"Deploy failed\");\n await prisma.job.update({ where: { id: jobId }, data: { status: \"FAILED\", error: e.message, finishedAt: new Date() } });\n\n const freshPreview = await prisma.preview.findUnique({ where: { id: preview.id } });\n if (!freshPreview) return;\n\n const lastLines = (freshPreview.logs || \"\").split(\"\\n\").slice(-10).join(\"\\n\");\n await updateStatus(preview.id, \"FAILED\");\n\n const failBody = buildPrCommentBody({\n owner: repoConfig.repoOwner,\n repo: repoConfig.repoName,\n prNumber: freshPreview.prNumber,\n status: `\uD83D\uDD34 Failed \u2014 last log lines:\\n\\`\\`\\`\\n${lastLines}\\n\\`\\`\\``,\n commitSha: freshPreview.commitSha,\n updatedAt: new Date(),\n ppBaseUrl: env.PP_BASE_URL,\n });\n\n if (freshPreview.giteaCommentId) {\n try {\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, freshPreview.giteaCommentId, failBody);\n } catch {}\n }\n }\n}\n\nasync function firstDeploy(\n jobId: number,\n preview: Preview & { repoConfig: RepoConfig },\n repoConfig: RepoConfig,\n user: User,\n commitSha: string,\n prNumber: number,\n prTitle: string,\n cloneUrl: string,\n) {\n const settings = await getAdminSettings();\n const ec2 = makeEc2Client(user);\n const previewId = preview.id;\n\n const activeCount = await prisma.preview.count({\n where: {\n repoConfig: { userId: user.id },\n status: { in: [\"PROVISIONING\", \"BUILDING\", \"RUNNING\"] },\n id: { not: previewId },\n },\n });\n\n if (activeCount >= settings.maxConcurrentInstancesPerUser) {\n const body = buildPrCommentBody({\n owner: repoConfig.repoOwner,\n repo: repoConfig.repoName,\n prNumber,\n status: `\uD83D\uDD34 Cannot provision preview \u2014 concurrent instance limit (${settings.maxConcurrentInstancesPerUser}) reached.`,\n commitSha,\n updatedAt: new Date(),\n ppBaseUrl: env.PP_BASE_URL,\n });\n const commentId = await postComment(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, body);\n await prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: commentId } });\n throw new Error(\"Concurrent instance limit reached\");\n }\n\n await updateStatus(previewId, \"PROVISIONING\", { commitSha, prNumber, prTitle });\n\n const commentBody = buildPrCommentBody({\n owner: repoConfig.repoOwner, repo: repoConfig.repoName, prNumber,\n status: \"\uD83D\uDFE1 Provisioning EC2 instance...\",\n commitSha, updatedAt: new Date(), ppBaseUrl: env.PP_BASE_URL,\n });\n let commentId = await postComment(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, commentBody);\n await prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: commentId } });\n\n checkAbort(previewId);\n\n const keyName = `pp-preview-${previewId}`;\n const { privateKey } = await generateAndImportKeyPair(ec2, keyName);\n const encPrivateKey = encrypt(privateKey);\n\n await prisma.preview.update({ where: { id: previewId }, data: { sshPrivateKey: encPrivateKey, sshKeyName: keyName } });\n\n checkAbort(previewId);\n\n const sgName = `pp-preview-${previewId}`;\n const securityGroupId = await createPreviewSecurityGroup(ec2, sgName, repoConfig.port);\n\n checkAbort(previewId);\n\n const instanceId = await launchInstance({\n ec2, region: user.awsRegion!,\n instanceType: repoConfig.instanceType,\n keyName,\n securityGroupId,\n tags: {\n \"pp:managed\": \"true\",\n \"pp:userId\": String(user.id),\n \"pp:repo\": `${repoConfig.repoOwner}/${repoConfig.repoName}`,\n \"pp:prNumber\": String(prNumber),\n \"pp:previewId\": String(previewId),\n },\n });\n\n await prisma.preview.update({ where: { id: previewId }, data: { instanceId } });\n\n await appendLog(previewId, `[PP] EC2 instance ${instanceId} launched. Waiting for it to be running...\\n`);\n\n checkAbort(previewId);\n\n const instanceIp = await waitForInstanceRunning(ec2, instanceId);\n await prisma.preview.update({ where: { id: previewId }, data: { instanceIp, port: repoConfig.port } });\n\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, commentId,\n buildPrCommentBody({\n owner: repoConfig.repoOwner, repo: repoConfig.repoName, prNumber,\n status: `\uD83D\uDFE1 Building... (EC2 ready at ${instanceIp})`,\n commitSha, updatedAt: new Date(), ppBaseUrl: env.PP_BASE_URL,\n })\n );\n\n await appendLog(previewId, `[PP] Instance running at ${instanceIp}. Waiting for SSH...\\n`);\n\n checkAbort(previewId);\n\n const sshSession = await connectSsh(instanceIp, privateKey, 300_000);\n activeSshSessions.set(previewId, sshSession);\n\n try {\n if (repoConfig.aptPackages.length > 0) {\n await runSshStep(previewId, sshSession, `sudo apt-get install -y ${repoConfig.aptPackages.join(\" \")}`);\n }\n\n const giteaPat = user.giteaPAT ? decrypt(user.giteaPAT) : \"\";\n const authCloneUrl = cloneUrl.replace(\"https://\", `https://${user.giteaUsername}:${giteaPat}@`);\n await runSshStep(previewId, sshSession, `git clone ${authCloneUrl} /opt/app`);\n await runSshStep(previewId, sshSession, `cd /opt/app && git fetch origin pull/${prNumber}/head:pp-pr && git checkout pp-pr`);\n\n await setupAndBuild(previewId, sshSession, repoConfig, preview, commitSha, true);\n\n await updateStatus(previewId, \"RUNNING\", { commitSha, instanceIp, port: repoConfig.port, lastActivityAt: new Date() });\n\n const freshPreview = await prisma.preview.findUnique({ where: { id: previewId } });\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, commentId,\n buildPrCommentBody({\n owner: repoConfig.repoOwner, repo: repoConfig.repoName, prNumber,\n status: `\uD83D\uDFE2 Live at http://${instanceIp}:${repoConfig.port}`,\n commitSha, updatedAt: new Date(), ppBaseUrl: env.PP_BASE_URL,\n })\n );\n } finally {\n sshSession.close();\n activeSshSessions.delete(previewId);\n }\n}\n\nasync function redeploy(\n jobId: number,\n preview: Preview & { repoConfig: RepoConfig },\n repoConfig: RepoConfig,\n user: User,\n commitSha: string,\n prNumber: number,\n prTitle: string,\n) {\n const previewId = preview.id;\n const instanceIp = preview.instanceIp!;\n const privateKey = decrypt(preview.sshPrivateKey!);\n\n const sshSession = await connectSsh(instanceIp, privateKey, 30_000);\n activeSshSessions.set(previewId, sshSession);\n\n await appendLog(previewId, `\\n--- Redeploy: ${commitSha} ---\\n`);\n\n const freshPreview = await prisma.preview.findUnique({ where: { id: previewId } });\n\n const commentBody = buildPrCommentBody({\n owner: repoConfig.repoOwner, repo: repoConfig.repoName, prNumber,\n status: `\uD83D\uDFE1 Building... (EC2 at ${instanceIp})`,\n commitSha, updatedAt: new Date(), ppBaseUrl: env.PP_BASE_URL,\n });\n const newCommentId = await postComment(user, repoConfig.repoOwner, repoConfig.repoName, prNumber, commentBody);\n await prisma.preview.update({ where: { id: previewId }, data: { giteaCommentId: newCommentId, commitSha } });\n\n try {\n if (repoConfig.useDockerCompose) {\n const composePath = repoConfig.composeFilePath || \"docker-compose.yml\";\n await runSshStep(previewId, sshSession, `cd /opt/app && docker compose -f ${composePath} down 2>&1 || true`);\n } else if (freshPreview?.pid) {\n await runSshStep(previewId, sshSession, `kill ${freshPreview.pid} 2>/dev/null || true; sleep 5; kill -9 ${freshPreview.pid} 2>/dev/null || true`);\n }\n\n await runSshStep(previewId, sshSession, `cd /opt/app && git fetch origin pull/${prNumber}/head:pp-pr && git checkout pp-pr && git reset --hard FETCH_HEAD`);\n\n await updateStatus(previewId, \"BUILDING\");\n await setupAndBuild(previewId, sshSession, repoConfig, preview, commitSha, false);\n\n await updateStatus(previewId, \"RUNNING\", { commitSha, lastActivityAt: new Date() });\n\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, newCommentId,\n buildPrCommentBody({\n owner: repoConfig.repoOwner, repo: repoConfig.repoName, prNumber,\n status: `\uD83D\uDFE2 Live at http://${instanceIp}:${repoConfig.port}`,\n commitSha, updatedAt: new Date(), ppBaseUrl: env.PP_BASE_URL,\n })\n );\n } finally {\n sshSession.close();\n activeSshSessions.delete(previewId);\n }\n}\n\nasync function setupAndBuild(\n previewId: number,\n sshSession: SshSession,\n repoConfig: RepoConfig,\n preview: Preview,\n commitSha: string,\n isFirstProvision: boolean,\n) {\n await detectAndUseNode(previewId, sshSession);\n\n const envVars = repoConfig.envVars as Record;\n const envContent = Object.entries(envVars).map(([k, v]) => `${k}=${v}`).join(\"\\n\");\n await runSshStep(previewId, sshSession, `cat > /opt/app/.env << 'PPEOF'\\n${envContent}\\nPPEOF`);\n\n if (isFirstProvision) {\n for (const cmd of repoConfig.setupCommands) {\n await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`);\n }\n }\n\n await updateStatus(previewId, \"BUILDING\");\n\n if (repoConfig.useDockerCompose) {\n const composePath = repoConfig.composeFilePath || \"docker-compose.yml\";\n await runSshStep(previewId, sshSession, `cd /opt/app && docker compose -f ${composePath} up -d --build --force-recreate 2>&1`);\n } else {\n for (const cmd of repoConfig.buildCommands) {\n await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`);\n }\n for (const cmd of repoConfig.postBuildCommands) {\n await runSshStep(previewId, sshSession, `cd /opt/app && ${cmd}`);\n }\n\n if (repoConfig.runCommand) {\n const res = await runSshStep(previewId, sshSession,\n `cd /opt/app && nohup ${repoConfig.runCommand} > /opt/app/pp.log 2>&1 & echo $!`\n );\n const pid = parseInt(res.stdout.trim(), 10);\n if (!isNaN(pid)) {\n await prisma.preview.update({ where: { id: previewId }, data: { pid } });\n }\n }\n }\n}\n\nasync function detectAndUseNode(previewId: number, sshSession: SshSession) {\n const nvmSource = `export NVM_DIR=\"/root/.nvm\" && source \"$NVM_DIR/nvm.sh\"`;\n const res = await runSshStep(previewId, sshSession, `${nvmSource} && [ -f /opt/app/.nvmrc ] && nvm install && nvm use || nvm use default 2>&1`, false);\n}\n\nasync function runSshStep(previewId: number, sshSession: SshSession, command: string, throwOnFail = true) {\n checkAbortSession(sshSession);\n await appendLog(previewId, `$ ${command}\\n`);\n const res = await sshSession.exec(command);\n if (res.stdout) await appendLog(previewId, res.stdout);\n if (res.stderr) await appendLog(previewId, res.stderr);\n if (throwOnFail && res.code !== 0) {\n throw new Error(`Command failed with exit code ${res.code}: ${command}`);\n }\n return res;\n}\n\nfunction checkAbortSession(session: SshSession) {\n if (session.aborted) throw new Error(\"ABORTED\");\n}\n\nconst abortSignals = new Set();\n\nexport function signalAbort(previewId: number) {\n abortSignals.add(previewId);\n abortJobForPreview(previewId);\n}\n\nfunction checkAbort(previewId: number) {\n if (abortSignals.has(previewId)) {\n abortSignals.delete(previewId);\n throw new Error(\"ABORTED\");\n }\n}\n\nexport async function stopPreview(previewId: number, reason: \"STOPPED\" | \"FAILED\" = \"STOPPED\") {\n const preview = await prisma.preview.findUnique({\n where: { id: previewId },\n include: { repoConfig: { include: { user: true } } },\n });\n if (!preview) return;\n\n const user = (preview.repoConfig as any).user as User;\n const repoConfig = preview.repoConfig;\n\n if (preview.instanceId) {\n const ec2 = makeEc2Client(user);\n try {\n await deleteKeyPairAws(ec2, `pp-preview-${previewId}`);\n } catch {}\n try {\n await deleteSecurityGroupAws(ec2, `pp-preview-${previewId}`);\n } catch {}\n try {\n await terminateInstance(ec2, preview.instanceId);\n } catch {}\n }\n\n await prisma.preview.update({\n where: { id: previewId },\n data: {\n status: reason,\n stoppedAt: new Date(),\n sshPrivateKey: null,\n sshKeyName: null,\n instanceId: null,\n },\n });\n\n const stoppedBody = buildPrCommentBody({\n owner: repoConfig.repoOwner,\n repo: repoConfig.repoName,\n prNumber: preview.prNumber,\n status: \"\u26AB Stopped (inactivity timeout / PR closed / manual stop)\",\n commitSha: preview.commitSha,\n updatedAt: new Date(),\n ppBaseUrl: env.PP_BASE_URL,\n });\n\n if (preview.giteaCommentId) {\n try {\n await updateComment(user, repoConfig.repoOwner, repoConfig.repoName, preview.giteaCommentId, stoppedBody);\n } catch {}\n }\n}\n"], - "mappings": "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", - "names": ["commentId"] -} diff --git a/backend/dist/services/ec2.js b/backend/dist/services/ec2.js deleted file mode 100644 index 73d1e09a..00000000 --- a/backend/dist/services/ec2.js +++ /dev/null @@ -1,244 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var ec2_exports = {}; -__export(ec2_exports, { - createPreviewSecurityGroup: () => createPreviewSecurityGroup, - deleteKeyPairAws: () => deleteKeyPairAws, - deleteSecurityGroupAws: () => deleteSecurityGroupAws, - describeAllManagedInstances: () => describeAllManagedInstances, - generateAndImportKeyPair: () => generateAndImportKeyPair, - generateSshKeyPair: () => generateSshKeyPair, - launchInstance: () => launchInstance, - makeEc2Client: () => makeEc2Client, - makeStsClient: () => makeStsClient, - terminateInstance: () => terminateInstance, - validateAwsCredentials: () => validateAwsCredentials, - waitForInstanceRunning: () => waitForInstanceRunning -}); -module.exports = __toCommonJS(ec2_exports); -var import_client_ec2 = require("@aws-sdk/client-ec2"); -var import_client_sts = require("@aws-sdk/client-sts"); -var import_crypto = require("crypto"); -var import_logger = require("../lib/logger"); -var import_encryption = require("../lib/encryption"); -const log = (0, import_logger.createLogger)("EC2"); -const UBUNTU_22_04_AMI = { - "us-east-1": "ami-0e86e20dae9224db8", - "us-east-2": "ami-0a0d9cf81c479446a", - "us-west-1": "ami-05c969369880fa2c2", - "us-west-2": "ami-03f8acd418785369b", - "eu-west-1": "ami-0694d931cee176e7d", - "eu-west-2": "ami-0f3d9639a5674d559", - "eu-west-3": "ami-022e307f4b9e39f45", - "eu-central-1": "ami-0faab6bdbac9486fb", - "ap-southeast-1": "ami-0823c236601fef765", - "ap-southeast-2": "ami-07620139298af599e", - "ap-northeast-1": "ami-0b7546e839d7ace12", - "ap-northeast-2": "ami-042e76978adeb8c48", - "ap-south-1": "ami-076e3a557efe1aa9c", - "sa-east-1": "ami-0eed58016fbe42de3", - "ca-central-1": "ami-024f768de9e73d4f4", - "eu-north-1": "ami-00381a880aa48c6c6", - "me-south-1": "ami-09574f34b8dcd2eac", - "af-south-1": "ami-08fdcf06b39fe83ec" -}; -function makeEc2Client(user) { - const accessKeyId = user.awsAccessKeyId ? (0, import_encryption.decrypt)(user.awsAccessKeyId) : ""; - const secretAccessKey = user.awsSecretAccessKey ? (0, import_encryption.decrypt)(user.awsSecretAccessKey) : ""; - return new import_client_ec2.EC2Client({ - region: user.awsRegion, - credentials: { accessKeyId, secretAccessKey } - }); -} -function makeStsClient(user) { - const accessKeyId = user.awsAccessKeyId ? (0, import_encryption.decrypt)(user.awsAccessKeyId) : ""; - const secretAccessKey = user.awsSecretAccessKey ? (0, import_encryption.decrypt)(user.awsSecretAccessKey) : ""; - return new import_client_sts.STSClient({ - region: user.awsRegion, - credentials: { accessKeyId, secretAccessKey } - }); -} -async function validateAwsCredentials(user) { - try { - const sts = makeStsClient(user); - const res = await sts.send(new import_client_sts.GetCallerIdentityCommand({})); - return { success: true, arn: res.Arn }; - } catch (e) { - return { success: false, error: e.message }; - } -} -function generateSshKeyPair() { - const { privateKey: privKeyPem, publicKey: pubKeyPem } = (0, import_crypto.generateKeyPairSync)("rsa", { - modulusLength: 2048, - publicKeyEncoding: { type: "spki", format: "pem" }, - privateKeyEncoding: { type: "pkcs1", format: "pem" } - }); - const pubKeyObj = (0, import_crypto.createPublicKey)(pubKeyPem); - const pubKeyDer = pubKeyObj.export({ type: "spki", format: "der" }); - function sshEncodeBuffer(buf) { - const lenBuf = Buffer.allocUnsafe(4); - lenBuf.writeUInt32BE(buf.length, 0); - return Buffer.concat([lenBuf, buf]); - } - const keyTypeStr = Buffer.from("ssh-rsa"); - const keyTypeEncoded = sshEncodeBuffer(keyTypeStr); - const base64Encoded = pubKeyDer.toString("base64"); - const openSshKey = `ssh-rsa ${Buffer.concat([keyTypeEncoded]).toString("base64")} pp-generated`; - return { privateKey: privKeyPem, publicKeyOpenssh: `ssh-rsa ${base64Encoded} pp-generated` }; -} -async function generateAndImportKeyPair(ec2, keyName) { - const { privateKey, publicKeyOpenssh } = generateSshKeyPair(); - await ec2.send(new import_client_ec2.ImportKeyPairCommand({ - KeyName: keyName, - PublicKeyMaterial: Buffer.from(publicKeyOpenssh) - })); - return { privateKey }; -} -async function createPreviewSecurityGroup(ec2, groupName, port) { - const describe = await ec2.send(new import_client_ec2.DescribeSecurityGroupsCommand({ - Filters: [{ Name: "group-name", Values: [groupName] }] - })); - if (describe.SecurityGroups && describe.SecurityGroups.length > 0) { - return describe.SecurityGroups[0].GroupId; - } - const res = await ec2.send(new import_client_ec2.CreateSecurityGroupCommand({ - GroupName: groupName, - Description: `PP Preview security group: ${groupName}` - })); - const groupId = res.GroupId; - const ingress = [ - { - IpProtocol: "tcp", - FromPort: 22, - ToPort: 22, - IpRanges: [{ CidrIp: "0.0.0.0/0" }] - } - ]; - if (port !== 22) { - ingress.push({ - IpProtocol: "tcp", - FromPort: port, - ToPort: port, - IpRanges: [{ CidrIp: "0.0.0.0/0" }] - }); - } - await ec2.send(new import_client_ec2.AuthorizeSecurityGroupIngressCommand({ - GroupId: groupId, - IpPermissions: ingress - })); - return groupId; -} -const BOOTSTRAP_SCRIPT = `#!/bin/bash -set -e -apt-get update -y -apt-get install -y curl git unzip build-essential -curl -fsSL https://get.docker.com | sh -systemctl enable docker -systemctl start docker -apt-get install -y docker-compose-plugin -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash -export NVM_DIR="/root/.nvm" -source "$NVM_DIR/nvm.sh" -nvm install --lts -nvm alias default lts/* -`; -async function launchInstance(opts) { - const ami = UBUNTU_22_04_AMI[opts.region] ?? UBUNTU_22_04_AMI["us-east-1"]; - const tagSpecs = Object.entries(opts.tags).map(([k, v]) => ({ Key: k, Value: v })); - tagSpecs.push({ Key: "Name", Value: `pp-preview-${opts.tags["pp:previewId"]}` }); - const res = await opts.ec2.send(new import_client_ec2.RunInstancesCommand({ - ImageId: ami, - InstanceType: opts.instanceType, - MinCount: 1, - MaxCount: 1, - KeyName: opts.keyName, - SecurityGroupIds: [opts.securityGroupId], - UserData: Buffer.from(BOOTSTRAP_SCRIPT).toString("base64"), - TagSpecifications: [ - { ResourceType: "instance", Tags: tagSpecs } - ] - })); - return res.Instances[0].InstanceId; -} -async function waitForInstanceRunning(ec2, instanceId, maxWaitMs = 3e5) { - const start = Date.now(); - while (Date.now() - start < maxWaitMs) { - const res = await ec2.send(new import_client_ec2.DescribeInstancesCommand({ - InstanceIds: [instanceId] - })); - const inst = res.Reservations?.[0]?.Instances?.[0]; - if (inst?.State?.Name === "running" && inst.PublicIpAddress) { - return inst.PublicIpAddress; - } - await sleep(5e3); - } - throw new Error(`Instance ${instanceId} did not reach running state within timeout`); -} -async function terminateInstance(ec2, instanceId) { - await ec2.send(new import_client_ec2.TerminateInstancesCommand({ InstanceIds: [instanceId] })); -} -async function deleteKeyPairAws(ec2, keyName) { - try { - await ec2.send(new import_client_ec2.DeleteKeyPairCommand({ KeyName: keyName })); - } catch (e) { - log.warn({ e, keyName }, "Failed to delete key pair"); - } -} -async function deleteSecurityGroupAws(ec2, groupName) { - try { - const describe = await ec2.send(new import_client_ec2.DescribeSecurityGroupsCommand({ - Filters: [{ Name: "group-name", Values: [groupName] }] - })); - const groupId = describe.SecurityGroups?.[0]?.GroupId; - if (groupId) { - await sleep(5e3); - await ec2.send(new import_client_ec2.DeleteSecurityGroupCommand({ GroupId: groupId })); - } - } catch (e) { - log.warn({ e, groupName }, "Failed to delete security group"); - } -} -async function describeAllManagedInstances(ec2) { - const res = await ec2.send(new import_client_ec2.DescribeInstancesCommand({ - Filters: [ - { Name: "tag:pp:managed", Values: ["true"] }, - { Name: "instance-state-name", Values: ["running", "pending", "stopping"] } - ] - })); - return (res.Reservations ?? []).flatMap((r) => r.Instances ?? []); -} -function sleep(ms) { - return new Promise((r) => setTimeout(r, ms)); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - createPreviewSecurityGroup, - deleteKeyPairAws, - deleteSecurityGroupAws, - describeAllManagedInstances, - generateAndImportKeyPair, - generateSshKeyPair, - launchInstance, - makeEc2Client, - makeStsClient, - terminateInstance, - validateAwsCredentials, - waitForInstanceRunning -}); -//# sourceMappingURL=ec2.js.map diff --git a/backend/dist/services/ec2.js.map b/backend/dist/services/ec2.js.map deleted file mode 100644 index 1562ba27..00000000 --- a/backend/dist/services/ec2.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/services/ec2.ts"], - "sourcesContent": ["import {\n EC2Client,\n RunInstancesCommand,\n TerminateInstancesCommand,\n DescribeInstancesCommand,\n CreateSecurityGroupCommand,\n DeleteSecurityGroupCommand,\n AuthorizeSecurityGroupIngressCommand,\n DescribeSecurityGroupsCommand,\n ImportKeyPairCommand,\n DeleteKeyPairCommand,\n CreateTagsCommand,\n} from \"@aws-sdk/client-ec2\";\nimport { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\nimport { generateKeyPairSync, createPublicKey } from \"crypto\";\nimport { createLogger } from \"../lib/logger\";\nimport { decrypt } from \"../lib/encryption\";\nimport type { User } from \"@prisma/client\";\n\nconst log = createLogger(\"EC2\");\n\nconst UBUNTU_22_04_AMI: Record = {\n \"us-east-1\": \"ami-0e86e20dae9224db8\",\n \"us-east-2\": \"ami-0a0d9cf81c479446a\",\n \"us-west-1\": \"ami-05c969369880fa2c2\",\n \"us-west-2\": \"ami-03f8acd418785369b\",\n \"eu-west-1\": \"ami-0694d931cee176e7d\",\n \"eu-west-2\": \"ami-0f3d9639a5674d559\",\n \"eu-west-3\": \"ami-022e307f4b9e39f45\",\n \"eu-central-1\": \"ami-0faab6bdbac9486fb\",\n \"ap-southeast-1\": \"ami-0823c236601fef765\",\n \"ap-southeast-2\": \"ami-07620139298af599e\",\n \"ap-northeast-1\": \"ami-0b7546e839d7ace12\",\n \"ap-northeast-2\": \"ami-042e76978adeb8c48\",\n \"ap-south-1\": \"ami-076e3a557efe1aa9c\",\n \"sa-east-1\": \"ami-0eed58016fbe42de3\",\n \"ca-central-1\": \"ami-024f768de9e73d4f4\",\n \"eu-north-1\": \"ami-00381a880aa48c6c6\",\n \"me-south-1\": \"ami-09574f34b8dcd2eac\",\n \"af-south-1\": \"ami-08fdcf06b39fe83ec\",\n};\n\nexport function makeEc2Client(user: User): EC2Client {\n const accessKeyId = user.awsAccessKeyId ? decrypt(user.awsAccessKeyId) : \"\";\n const secretAccessKey = user.awsSecretAccessKey ? decrypt(user.awsSecretAccessKey) : \"\";\n return new EC2Client({\n region: user.awsRegion!,\n credentials: { accessKeyId, secretAccessKey },\n });\n}\n\nexport function makeStsClient(user: User): STSClient {\n const accessKeyId = user.awsAccessKeyId ? decrypt(user.awsAccessKeyId) : \"\";\n const secretAccessKey = user.awsSecretAccessKey ? decrypt(user.awsSecretAccessKey) : \"\";\n return new STSClient({\n region: user.awsRegion!,\n credentials: { accessKeyId, secretAccessKey },\n });\n}\n\nexport async function validateAwsCredentials(user: User): Promise<{ success: boolean; arn?: string; error?: string }> {\n try {\n const sts = makeStsClient(user);\n const res = await sts.send(new GetCallerIdentityCommand({}));\n return { success: true, arn: res.Arn };\n } catch (e: any) {\n return { success: false, error: e.message };\n }\n}\n\nexport function generateSshKeyPair(): { privateKey: string; publicKeyOpenssh: string } {\n const { privateKey: privKeyPem, publicKey: pubKeyPem } = generateKeyPairSync(\"rsa\", {\n modulusLength: 2048,\n publicKeyEncoding: { type: \"spki\", format: \"pem\" },\n privateKeyEncoding: { type: \"pkcs1\", format: \"pem\" },\n });\n\n const pubKeyObj = createPublicKey(pubKeyPem);\n const pubKeyDer = pubKeyObj.export({ type: \"spki\", format: \"der\" });\n\n function sshEncodeBuffer(buf: Buffer): Buffer {\n const lenBuf = Buffer.allocUnsafe(4);\n lenBuf.writeUInt32BE(buf.length, 0);\n return Buffer.concat([lenBuf, buf]);\n }\n\n const keyTypeStr = Buffer.from(\"ssh-rsa\");\n const keyTypeEncoded = sshEncodeBuffer(keyTypeStr);\n\n const base64Encoded = pubKeyDer.toString(\"base64\");\n const openSshKey = `ssh-rsa ${Buffer.concat([keyTypeEncoded]).toString(\"base64\")} pp-generated`;\n\n return { privateKey: privKeyPem, publicKeyOpenssh: `ssh-rsa ${base64Encoded} pp-generated` };\n}\n\nexport async function generateAndImportKeyPair(ec2: EC2Client, keyName: string): Promise<{ privateKey: string }> {\n const { privateKey, publicKeyOpenssh } = generateSshKeyPair();\n await ec2.send(new ImportKeyPairCommand({\n KeyName: keyName,\n PublicKeyMaterial: Buffer.from(publicKeyOpenssh),\n }));\n return { privateKey };\n}\n\nexport async function createPreviewSecurityGroup(ec2: EC2Client, groupName: string, port: number): Promise {\n const describe = await ec2.send(new DescribeSecurityGroupsCommand({\n Filters: [{ Name: \"group-name\", Values: [groupName] }],\n }));\n if (describe.SecurityGroups && describe.SecurityGroups.length > 0) {\n return describe.SecurityGroups[0].GroupId!;\n }\n\n const res = await ec2.send(new CreateSecurityGroupCommand({\n GroupName: groupName,\n Description: `PP Preview security group: ${groupName}`,\n }));\n const groupId = res.GroupId!;\n\n const ingress: any[] = [\n {\n IpProtocol: \"tcp\",\n FromPort: 22,\n ToPort: 22,\n IpRanges: [{ CidrIp: \"0.0.0.0/0\" }],\n },\n ];\n if (port !== 22) {\n ingress.push({\n IpProtocol: \"tcp\",\n FromPort: port,\n ToPort: port,\n IpRanges: [{ CidrIp: \"0.0.0.0/0\" }],\n });\n }\n\n await ec2.send(new AuthorizeSecurityGroupIngressCommand({\n GroupId: groupId,\n IpPermissions: ingress,\n }));\n return groupId;\n}\n\nconst BOOTSTRAP_SCRIPT = `#!/bin/bash\nset -e\napt-get update -y\napt-get install -y curl git unzip build-essential\ncurl -fsSL https://get.docker.com | sh\nsystemctl enable docker\nsystemctl start docker\napt-get install -y docker-compose-plugin\ncurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\nexport NVM_DIR=\"/root/.nvm\"\nsource \"$NVM_DIR/nvm.sh\"\nnvm install --lts\nnvm alias default lts/*\n`;\n\nexport async function launchInstance(opts: {\n ec2: EC2Client;\n region: string;\n instanceType: string;\n keyName: string;\n securityGroupId: string;\n tags: Record;\n}): Promise {\n const ami = UBUNTU_22_04_AMI[opts.region] ?? UBUNTU_22_04_AMI[\"us-east-1\"];\n const tagSpecs = Object.entries(opts.tags).map(([k, v]) => ({ Key: k, Value: v }));\n tagSpecs.push({ Key: \"Name\", Value: `pp-preview-${opts.tags[\"pp:previewId\"]}` });\n\n const res = await opts.ec2.send(new RunInstancesCommand({\n ImageId: ami,\n InstanceType: opts.instanceType as any,\n MinCount: 1,\n MaxCount: 1,\n KeyName: opts.keyName,\n SecurityGroupIds: [opts.securityGroupId],\n UserData: Buffer.from(BOOTSTRAP_SCRIPT).toString(\"base64\"),\n TagSpecifications: [\n { ResourceType: \"instance\", Tags: tagSpecs },\n ],\n }));\n\n return res.Instances![0].InstanceId!;\n}\n\nexport async function waitForInstanceRunning(ec2: EC2Client, instanceId: string, maxWaitMs = 300_000): Promise {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n const res = await ec2.send(new DescribeInstancesCommand({\n InstanceIds: [instanceId],\n }));\n const inst = res.Reservations?.[0]?.Instances?.[0];\n if (inst?.State?.Name === \"running\" && inst.PublicIpAddress) {\n return inst.PublicIpAddress;\n }\n await sleep(5000);\n }\n throw new Error(`Instance ${instanceId} did not reach running state within timeout`);\n}\n\nexport async function terminateInstance(ec2: EC2Client, instanceId: string): Promise {\n await ec2.send(new TerminateInstancesCommand({ InstanceIds: [instanceId] }));\n}\n\nexport async function deleteKeyPairAws(ec2: EC2Client, keyName: string): Promise {\n try {\n await ec2.send(new DeleteKeyPairCommand({ KeyName: keyName }));\n } catch (e) {\n log.warn({ e, keyName }, \"Failed to delete key pair\");\n }\n}\n\nexport async function deleteSecurityGroupAws(ec2: EC2Client, groupName: string): Promise {\n try {\n const describe = await ec2.send(new DescribeSecurityGroupsCommand({\n Filters: [{ Name: \"group-name\", Values: [groupName] }],\n }));\n const groupId = describe.SecurityGroups?.[0]?.GroupId;\n if (groupId) {\n await sleep(5000);\n await ec2.send(new DeleteSecurityGroupCommand({ GroupId: groupId }));\n }\n } catch (e) {\n log.warn({ e, groupName }, \"Failed to delete security group\");\n }\n}\n\nexport async function describeAllManagedInstances(ec2: EC2Client): Promise {\n const res = await ec2.send(new DescribeInstancesCommand({\n Filters: [\n { Name: \"tag:pp:managed\", Values: [\"true\"] },\n { Name: \"instance-state-name\", Values: [\"running\", \"pending\", \"stopping\"] },\n ],\n }));\n return (res.Reservations ?? []).flatMap(r => r.Instances ?? []);\n}\n\nfunction sleep(ms: number) {\n return new Promise(r => setTimeout(r, ms));\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAYO;AACP,wBAAoD;AACpD,oBAAqD;AACrD,oBAA6B;AAC7B,wBAAwB;AAGxB,MAAM,UAAM,4BAAa,KAAK;AAE9B,MAAM,mBAA2C;AAAA,EAC/C,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAChB;AAEO,SAAS,cAAc,MAAuB;AACnD,QAAM,cAAc,KAAK,qBAAiB,2BAAQ,KAAK,cAAc,IAAI;AACzE,QAAM,kBAAkB,KAAK,yBAAqB,2BAAQ,KAAK,kBAAkB,IAAI;AACrF,SAAO,IAAI,4BAAU;AAAA,IACnB,QAAQ,KAAK;AAAA,IACb,aAAa,EAAE,aAAa,gBAAgB;AAAA,EAC9C,CAAC;AACH;AAEO,SAAS,cAAc,MAAuB;AACnD,QAAM,cAAc,KAAK,qBAAiB,2BAAQ,KAAK,cAAc,IAAI;AACzE,QAAM,kBAAkB,KAAK,yBAAqB,2BAAQ,KAAK,kBAAkB,IAAI;AACrF,SAAO,IAAI,4BAAU;AAAA,IACnB,QAAQ,KAAK;AAAA,IACb,aAAa,EAAE,aAAa,gBAAgB;AAAA,EAC9C,CAAC;AACH;AAEA,eAAsB,uBAAuB,MAAyE;AACpH,MAAI;AACF,UAAM,MAAM,cAAc,IAAI;AAC9B,UAAM,MAAM,MAAM,IAAI,KAAK,IAAI,2CAAyB,CAAC,CAAC,CAAC;AAC3D,WAAO,EAAE,SAAS,MAAM,KAAK,IAAI,IAAI;AAAA,EACvC,SAAS,GAAQ;AACf,WAAO,EAAE,SAAS,OAAO,OAAO,EAAE,QAAQ;AAAA,EAC5C;AACF;AAEO,SAAS,qBAAuE;AACrF,QAAM,EAAE,YAAY,YAAY,WAAW,UAAU,QAAI,mCAAoB,OAAO;AAAA,IAClF,eAAe;AAAA,IACf,mBAAmB,EAAE,MAAM,QAAQ,QAAQ,MAAM;AAAA,IACjD,oBAAoB,EAAE,MAAM,SAAS,QAAQ,MAAM;AAAA,EACrD,CAAC;AAED,QAAM,gBAAY,+BAAgB,SAAS;AAC3C,QAAM,YAAY,UAAU,OAAO,EAAE,MAAM,QAAQ,QAAQ,MAAM,CAAC;AAElE,WAAS,gBAAgB,KAAqB;AAC5C,UAAM,SAAS,OAAO,YAAY,CAAC;AACnC,WAAO,cAAc,IAAI,QAAQ,CAAC;AAClC,WAAO,OAAO,OAAO,CAAC,QAAQ,GAAG,CAAC;AAAA,EACpC;AAEA,QAAM,aAAa,OAAO,KAAK,SAAS;AACxC,QAAM,iBAAiB,gBAAgB,UAAU;AAEjD,QAAM,gBAAgB,UAAU,SAAS,QAAQ;AACjD,QAAM,aAAa,WAAW,OAAO,OAAO,CAAC,cAAc,CAAC,EAAE,SAAS,QAAQ,CAAC;AAEhF,SAAO,EAAE,YAAY,YAAY,kBAAkB,WAAW,aAAa,gBAAgB;AAC7F;AAEA,eAAsB,yBAAyB,KAAgB,SAAkD;AAC/G,QAAM,EAAE,YAAY,iBAAiB,IAAI,mBAAmB;AAC5D,QAAM,IAAI,KAAK,IAAI,uCAAqB;AAAA,IACtC,SAAS;AAAA,IACT,mBAAmB,OAAO,KAAK,gBAAgB;AAAA,EACjD,CAAC,CAAC;AACF,SAAO,EAAE,WAAW;AACtB;AAEA,eAAsB,2BAA2B,KAAgB,WAAmB,MAA+B;AACjH,QAAM,WAAW,MAAM,IAAI,KAAK,IAAI,gDAA8B;AAAA,IAChE,SAAS,CAAC,EAAE,MAAM,cAAc,QAAQ,CAAC,SAAS,EAAE,CAAC;AAAA,EACvD,CAAC,CAAC;AACF,MAAI,SAAS,kBAAkB,SAAS,eAAe,SAAS,GAAG;AACjE,WAAO,SAAS,eAAe,CAAC,EAAE;AAAA,EACpC;AAEA,QAAM,MAAM,MAAM,IAAI,KAAK,IAAI,6CAA2B;AAAA,IACxD,WAAW;AAAA,IACX,aAAa,8BAA8B,SAAS;AAAA,EACtD,CAAC,CAAC;AACF,QAAM,UAAU,IAAI;AAEpB,QAAM,UAAiB;AAAA,IACrB;AAAA,MACE,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,QAAQ,YAAY,CAAC;AAAA,IACpC;AAAA,EACF;AACA,MAAI,SAAS,IAAI;AACf,YAAQ,KAAK;AAAA,MACX,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU,CAAC,EAAE,QAAQ,YAAY,CAAC;AAAA,IACpC,CAAC;AAAA,EACH;AAEA,QAAM,IAAI,KAAK,IAAI,uDAAqC;AAAA,IACtD,SAAS;AAAA,IACT,eAAe;AAAA,EACjB,CAAC,CAAC;AACF,SAAO;AACT;AAEA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAezB,eAAsB,eAAe,MAOjB;AAClB,QAAM,MAAM,iBAAiB,KAAK,MAAM,KAAK,iBAAiB,WAAW;AACzE,QAAM,WAAW,OAAO,QAAQ,KAAK,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO,EAAE,EAAE;AACjF,WAAS,KAAK,EAAE,KAAK,QAAQ,OAAO,cAAc,KAAK,KAAK,cAAc,CAAC,GAAG,CAAC;AAE/E,QAAM,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,sCAAoB;AAAA,IACtD,SAAS;AAAA,IACT,cAAc,KAAK;AAAA,IACnB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,SAAS,KAAK;AAAA,IACd,kBAAkB,CAAC,KAAK,eAAe;AAAA,IACvC,UAAU,OAAO,KAAK,gBAAgB,EAAE,SAAS,QAAQ;AAAA,IACzD,mBAAmB;AAAA,MACjB,EAAE,cAAc,YAAY,MAAM,SAAS;AAAA,IAC7C;AAAA,EACF,CAAC,CAAC;AAEF,SAAO,IAAI,UAAW,CAAC,EAAE;AAC3B;AAEA,eAAsB,uBAAuB,KAAgB,YAAoB,YAAY,KAA0B;AACrH,QAAM,QAAQ,KAAK,IAAI;AACvB,SAAO,KAAK,IAAI,IAAI,QAAQ,WAAW;AACrC,UAAM,MAAM,MAAM,IAAI,KAAK,IAAI,2CAAyB;AAAA,MACtD,aAAa,CAAC,UAAU;AAAA,IAC1B,CAAC,CAAC;AACF,UAAM,OAAO,IAAI,eAAe,CAAC,GAAG,YAAY,CAAC;AACjD,QAAI,MAAM,OAAO,SAAS,aAAa,KAAK,iBAAiB;AAC3D,aAAO,KAAK;AAAA,IACd;AACA,UAAM,MAAM,GAAI;AAAA,EAClB;AACA,QAAM,IAAI,MAAM,YAAY,UAAU,6CAA6C;AACrF;AAEA,eAAsB,kBAAkB,KAAgB,YAAmC;AACzF,QAAM,IAAI,KAAK,IAAI,4CAA0B,EAAE,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC;AAC7E;AAEA,eAAsB,iBAAiB,KAAgB,SAAgC;AACrF,MAAI;AACF,UAAM,IAAI,KAAK,IAAI,uCAAqB,EAAE,SAAS,QAAQ,CAAC,CAAC;AAAA,EAC/D,SAAS,GAAG;AACV,QAAI,KAAK,EAAE,GAAG,QAAQ,GAAG,2BAA2B;AAAA,EACtD;AACF;AAEA,eAAsB,uBAAuB,KAAgB,WAAkC;AAC7F,MAAI;AACF,UAAM,WAAW,MAAM,IAAI,KAAK,IAAI,gDAA8B;AAAA,MAChE,SAAS,CAAC,EAAE,MAAM,cAAc,QAAQ,CAAC,SAAS,EAAE,CAAC;AAAA,IACvD,CAAC,CAAC;AACF,UAAM,UAAU,SAAS,iBAAiB,CAAC,GAAG;AAC9C,QAAI,SAAS;AACX,YAAM,MAAM,GAAI;AAChB,YAAM,IAAI,KAAK,IAAI,6CAA2B,EAAE,SAAS,QAAQ,CAAC,CAAC;AAAA,IACrE;AAAA,EACF,SAAS,GAAG;AACV,QAAI,KAAK,EAAE,GAAG,UAAU,GAAG,iCAAiC;AAAA,EAC9D;AACF;AAEA,eAAsB,4BAA4B,KAAgC;AAChF,QAAM,MAAM,MAAM,IAAI,KAAK,IAAI,2CAAyB;AAAA,IACtD,SAAS;AAAA,MACP,EAAE,MAAM,kBAAkB,QAAQ,CAAC,MAAM,EAAE;AAAA,MAC3C,EAAE,MAAM,uBAAuB,QAAQ,CAAC,WAAW,WAAW,UAAU,EAAE;AAAA,IAC5E;AAAA,EACF,CAAC,CAAC;AACF,UAAQ,IAAI,gBAAgB,CAAC,GAAG,QAAQ,OAAK,EAAE,aAAa,CAAC,CAAC;AAChE;AAEA,SAAS,MAAM,IAAY;AACzB,SAAO,IAAI,QAAQ,OAAK,WAAW,GAAG,EAAE,CAAC;AAC3C;", - "names": [] -} diff --git a/backend/dist/services/gitea.js b/backend/dist/services/gitea.js deleted file mode 100644 index b32e182d..00000000 --- a/backend/dist/services/gitea.js +++ /dev/null @@ -1,170 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var gitea_exports = {}; -__export(gitea_exports, { - buildPrCommentBody: () => buildPrCommentBody, - checkUserPermission: () => checkUserPermission, - deleteWebhook: () => deleteWebhook, - fetchUserRepos: () => fetchUserRepos, - getRepoCollaboratorPermission: () => getRepoCollaboratorPermission, - giteaApi: () => giteaApi, - postComment: () => postComment, - registerWebhook: () => registerWebhook, - updateComment: () => updateComment, - updateWebhookSecret: () => updateWebhookSecret, - validateGiteaUrl: () => validateGiteaUrl -}); -module.exports = __toCommonJS(gitea_exports); -var import_axios = __toESM(require("axios")); -var import_encryption = require("../lib/encryption"); -function giteaApi(user) { - const pat = user.giteaPAT ? (0, import_encryption.decrypt)(user.giteaPAT) : ""; - return import_axios.default.create({ - baseURL: `${user.giteaInstanceUrl}/api/v1`, - headers: { - Authorization: `token ${pat}`, - "Content-Type": "application/json" - }, - timeout: 15e3 - }); -} -async function validateGiteaUrl(url) { - try { - const res = await import_axios.default.get(`${url}/api/v1/version`, { timeout: 1e4 }); - return { success: true, version: res.data.version }; - } catch (e) { - return { success: false, error: e.message }; - } -} -async function fetchUserRepos(user) { - const api = giteaApi(user); - const repos = []; - let page = 1; - while (true) { - const res = await api.get(`/repos/search?limit=50&page=${page}`); - const data = res.data?.data ?? []; - if (data.length === 0) break; - repos.push(...data); - if (data.length < 50) break; - page++; - } - return repos; -} -async function registerWebhook(user, owner, repo, webhookUrl, secret) { - const api = giteaApi(user); - const res = await api.post(`/repos/${owner}/${repo}/hooks`, { - type: "gitea", - config: { - url: webhookUrl, - secret, - content_type: "json" - }, - events: ["pull_request", "issue_comment"], - active: true - }); - return res.data.id; -} -async function deleteWebhook(user, owner, repo, hookId) { - const api = giteaApi(user); - await api.delete(`/repos/${owner}/${repo}/hooks/${hookId}`); -} -async function updateWebhookSecret(user, owner, repo, hookId, webhookUrl, newSecret) { - const api = giteaApi(user); - await api.patch(`/repos/${owner}/${repo}/hooks/${hookId}`, { - config: { - url: webhookUrl, - secret: newSecret, - content_type: "json" - }, - events: ["pull_request", "issue_comment"], - active: true - }); -} -async function postComment(user, owner, repo, issueNumber, body) { - const api = giteaApi(user); - const res = await api.post(`/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body }); - return res.data.id; -} -async function updateComment(user, owner, repo, commentId, body) { - const api = giteaApi(user); - await api.patch(`/repos/${owner}/${repo}/issues/comments/${commentId}`, { body }); -} -async function checkUserPermission(user, owner, repo, username) { - try { - const api = giteaApi(user); - const res = await api.get(`/repos/${owner}/${repo}/collaborators/${username}`); - return res.status === 204; - } catch { - return false; - } -} -async function getRepoCollaboratorPermission(user, owner, repo, username) { - try { - const api = giteaApi(user); - const res = await api.get(`/repos/${owner}/${repo}/collaborators/${username}/permission`); - return res.data?.permission ?? null; - } catch { - return null; - } -} -function buildPrCommentBody(opts) { - const { owner, repo, prNumber, status, commitSha, updatedAt, ppBaseUrl, lastLogLines, instanceIp, port } = opts; - const ts = updatedAt.toISOString().replace("T", " ").slice(0, 19) + " UTC"; - let statusLine = status; - if (lastLogLines) { - statusLine += ` - -\`\`\` -${lastLogLines} -\`\`\``; - } - return `## \u{1F680} PR Preview \u2014 \`${owner}/${repo}\` #${prNumber} - -**Status:** ${statusLine} -**Commit:** \`${commitSha.slice(0, 8)}\` -**Updated:** ${ts} - ---- -_Powered by [PR Previews](${ppBaseUrl})_`; -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - buildPrCommentBody, - checkUserPermission, - deleteWebhook, - fetchUserRepos, - getRepoCollaboratorPermission, - giteaApi, - postComment, - registerWebhook, - updateComment, - updateWebhookSecret, - validateGiteaUrl -}); -//# sourceMappingURL=gitea.js.map diff --git a/backend/dist/services/gitea.js.map b/backend/dist/services/gitea.js.map deleted file mode 100644 index 3bb4339d..00000000 --- a/backend/dist/services/gitea.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/services/gitea.ts"], - "sourcesContent": ["import axios from \"axios\";\nimport { decrypt } from \"../lib/encryption\";\nimport type { User } from \"@prisma/client\";\n\nexport function giteaApi(user: User) {\n const pat = user.giteaPAT ? decrypt(user.giteaPAT) : \"\";\n return axios.create({\n baseURL: `${user.giteaInstanceUrl}/api/v1`,\n headers: {\n Authorization: `token ${pat}`,\n \"Content-Type\": \"application/json\",\n },\n timeout: 15000,\n });\n}\n\nexport async function validateGiteaUrl(url: string): Promise<{ success: boolean; version?: string; error?: string }> {\n try {\n const res = await axios.get(`${url}/api/v1/version`, { timeout: 10000 });\n return { success: true, version: res.data.version };\n } catch (e: any) {\n return { success: false, error: e.message };\n }\n}\n\nexport async function fetchUserRepos(user: User): Promise {\n const api = giteaApi(user);\n const repos: any[] = [];\n let page = 1;\n while (true) {\n const res = await api.get(`/repos/search?limit=50&page=${page}`);\n const data = res.data?.data ?? [];\n if (data.length === 0) break;\n repos.push(...data);\n if (data.length < 50) break;\n page++;\n }\n return repos;\n}\n\nexport async function registerWebhook(user: User, owner: string, repo: string, webhookUrl: string, secret: string): Promise {\n const api = giteaApi(user);\n const res = await api.post(`/repos/${owner}/${repo}/hooks`, {\n type: \"gitea\",\n config: {\n url: webhookUrl,\n secret,\n content_type: \"json\",\n },\n events: [\"pull_request\", \"issue_comment\"],\n active: true,\n });\n return res.data.id;\n}\n\nexport async function deleteWebhook(user: User, owner: string, repo: string, hookId: string): Promise {\n const api = giteaApi(user);\n await api.delete(`/repos/${owner}/${repo}/hooks/${hookId}`);\n}\n\nexport async function updateWebhookSecret(user: User, owner: string, repo: string, hookId: string, webhookUrl: string, newSecret: string): Promise {\n const api = giteaApi(user);\n await api.patch(`/repos/${owner}/${repo}/hooks/${hookId}`, {\n config: {\n url: webhookUrl,\n secret: newSecret,\n content_type: \"json\",\n },\n events: [\"pull_request\", \"issue_comment\"],\n active: true,\n });\n}\n\nexport async function postComment(user: User, owner: string, repo: string, issueNumber: number, body: string): Promise {\n const api = giteaApi(user);\n const res = await api.post(`/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body });\n return res.data.id;\n}\n\nexport async function updateComment(user: User, owner: string, repo: string, commentId: number, body: string): Promise {\n const api = giteaApi(user);\n await api.patch(`/repos/${owner}/${repo}/issues/comments/${commentId}`, { body });\n}\n\nexport async function checkUserPermission(user: User, owner: string, repo: string, username: string): Promise {\n try {\n const api = giteaApi(user);\n const res = await api.get(`/repos/${owner}/${repo}/collaborators/${username}`);\n return res.status === 204;\n } catch {\n return false;\n }\n}\n\nexport async function getRepoCollaboratorPermission(user: User, owner: string, repo: string, username: string): Promise {\n try {\n const api = giteaApi(user);\n const res = await api.get(`/repos/${owner}/${repo}/collaborators/${username}/permission`);\n return res.data?.permission ?? null;\n } catch {\n return null;\n }\n}\n\nexport function buildPrCommentBody(opts: {\n owner: string;\n repo: string;\n prNumber: number;\n status: string;\n commitSha: string;\n updatedAt: Date;\n ppBaseUrl: string;\n lastLogLines?: string;\n instanceIp?: string;\n port?: number;\n}): string {\n const { owner, repo, prNumber, status, commitSha, updatedAt, ppBaseUrl, lastLogLines, instanceIp, port } = opts;\n const ts = updatedAt.toISOString().replace(\"T\", \" \").slice(0, 19) + \" UTC\";\n\n let statusLine = status;\n if (lastLogLines) {\n statusLine += `\\n\\n\\`\\`\\`\\n${lastLogLines}\\n\\`\\`\\``;\n }\n\n return `## \uD83D\uDE80 PR Preview \u2014 \\`${owner}/${repo}\\` #${prNumber}\n\n**Status:** ${statusLine}\n**Commit:** \\`${commitSha.slice(0, 8)}\\`\n**Updated:** ${ts}\n\n---\n_Powered by [PR Previews](${ppBaseUrl})_`;\n}\n"], - "mappings": "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", - "names": ["axios"] -} diff --git a/backend/dist/services/orphanCleanup.js b/backend/dist/services/orphanCleanup.js deleted file mode 100644 index 721a6df4..00000000 --- a/backend/dist/services/orphanCleanup.js +++ /dev/null @@ -1,74 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var orphanCleanup_exports = {}; -__export(orphanCleanup_exports, { - runOrphanCleanup: () => runOrphanCleanup -}); -module.exports = __toCommonJS(orphanCleanup_exports); -var import_db = require("../lib/db"); -var import_logger = require("../lib/logger"); -var import_ec2 = require("./ec2"); -const log = (0, import_logger.createLogger)("ORPHAN_CLEANUP"); -async function runOrphanCleanup() { - log.info("Running orphan EC2 instance cleanup"); - const users = await import_db.prisma.user.findMany({ - where: { - awsAccessKeyId: { not: null }, - awsSecretAccessKey: { not: null }, - awsRegion: { not: null } - } - }); - const activePreviews = await import_db.prisma.preview.findMany({ - where: { status: { notIn: ["STOPPED", "IGNORED"] }, instanceId: { not: null } }, - select: { id: true, instanceId: true } - }); - const activeInstanceIds = new Set(activePreviews.map((p) => p.instanceId)); - for (const user of users) { - try { - const ec2 = (0, import_ec2.makeEc2Client)(user); - const instances = await (0, import_ec2.describeAllManagedInstances)(ec2); - for (const inst of instances) { - const instanceId = inst.InstanceId; - if (!instanceId) continue; - const tags = Object.fromEntries((inst.Tags || []).map((t) => [t.Key, t.Value])); - const previewId = parseInt(tags["pp:previewId"] || "0", 10); - if (!activeInstanceIds.has(instanceId)) { - log.info({ instanceId, previewId }, "Terminating orphan instance"); - try { - const keyName = `pp-preview-${previewId}`; - const sgName = `pp-preview-${previewId}`; - await (0, import_ec2.deleteKeyPairAws)(ec2, keyName); - await (0, import_ec2.terminateInstance)(ec2, instanceId); - setTimeout(() => (0, import_ec2.deleteSecurityGroupAws)(ec2, sgName), 3e4); - } catch (e) { - log.warn({ e, instanceId }, "Failed to terminate orphan"); - } - } - } - } catch (e) { - log.warn({ e, userId: user.id }, "Failed to check orphans for user"); - } - } - log.info("Orphan cleanup complete"); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - runOrphanCleanup -}); -//# sourceMappingURL=orphanCleanup.js.map diff --git a/backend/dist/services/orphanCleanup.js.map b/backend/dist/services/orphanCleanup.js.map deleted file mode 100644 index 51725c23..00000000 --- a/backend/dist/services/orphanCleanup.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/services/orphanCleanup.ts"], - "sourcesContent": ["import { prisma } from \"../lib/db\";\nimport { createLogger } from \"../lib/logger\";\nimport { makeEc2Client, describeAllManagedInstances, terminateInstance, deleteKeyPairAws, deleteSecurityGroupAws } from \"./ec2\";\n\nconst log = createLogger(\"ORPHAN_CLEANUP\");\n\nexport async function runOrphanCleanup() {\n log.info(\"Running orphan EC2 instance cleanup\");\n\n const users = await prisma.user.findMany({\n where: {\n awsAccessKeyId: { not: null },\n awsSecretAccessKey: { not: null },\n awsRegion: { not: null },\n },\n });\n\n const activePreviews = await prisma.preview.findMany({\n where: { status: { notIn: [\"STOPPED\", \"IGNORED\"] }, instanceId: { not: null } },\n select: { id: true, instanceId: true },\n });\n const activeInstanceIds = new Set(activePreviews.map(p => p.instanceId!));\n\n for (const user of users) {\n try {\n const ec2 = makeEc2Client(user as any);\n const instances = await describeAllManagedInstances(ec2);\n\n for (const inst of instances) {\n const instanceId = inst.InstanceId;\n if (!instanceId) continue;\n\n const tags = Object.fromEntries((inst.Tags || []).map((t: any) => [t.Key, t.Value]));\n const previewId = parseInt(tags[\"pp:previewId\"] || \"0\", 10);\n\n if (!activeInstanceIds.has(instanceId)) {\n log.info({ instanceId, previewId }, \"Terminating orphan instance\");\n try {\n const keyName = `pp-preview-${previewId}`;\n const sgName = `pp-preview-${previewId}`;\n await deleteKeyPairAws(ec2, keyName);\n await terminateInstance(ec2, instanceId);\n setTimeout(() => deleteSecurityGroupAws(ec2, sgName), 30_000);\n } catch (e) {\n log.warn({ e, instanceId }, \"Failed to terminate orphan\");\n }\n }\n }\n } catch (e) {\n log.warn({ e, userId: user.id }, \"Failed to check orphans for user\");\n }\n }\n\n log.info(\"Orphan cleanup complete\");\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAuB;AACvB,oBAA6B;AAC7B,iBAAwH;AAExH,MAAM,UAAM,4BAAa,gBAAgB;AAEzC,eAAsB,mBAAmB;AACvC,MAAI,KAAK,qCAAqC;AAE9C,QAAM,QAAQ,MAAM,iBAAO,KAAK,SAAS;AAAA,IACvC,OAAO;AAAA,MACL,gBAAgB,EAAE,KAAK,KAAK;AAAA,MAC5B,oBAAoB,EAAE,KAAK,KAAK;AAAA,MAChC,WAAW,EAAE,KAAK,KAAK;AAAA,IACzB;AAAA,EACF,CAAC;AAED,QAAM,iBAAiB,MAAM,iBAAO,QAAQ,SAAS;AAAA,IACnD,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,WAAW,SAAS,EAAE,GAAG,YAAY,EAAE,KAAK,KAAK,EAAE;AAAA,IAC9E,QAAQ,EAAE,IAAI,MAAM,YAAY,KAAK;AAAA,EACvC,CAAC;AACD,QAAM,oBAAoB,IAAI,IAAI,eAAe,IAAI,OAAK,EAAE,UAAW,CAAC;AAExE,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,YAAM,UAAM,0BAAc,IAAW;AACrC,YAAM,YAAY,UAAM,wCAA4B,GAAG;AAEvD,iBAAW,QAAQ,WAAW;AAC5B,cAAM,aAAa,KAAK;AACxB,YAAI,CAAC,WAAY;AAEjB,cAAM,OAAO,OAAO,aAAa,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAW,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACnF,cAAM,YAAY,SAAS,KAAK,cAAc,KAAK,KAAK,EAAE;AAE1D,YAAI,CAAC,kBAAkB,IAAI,UAAU,GAAG;AACtC,cAAI,KAAK,EAAE,YAAY,UAAU,GAAG,6BAA6B;AACjE,cAAI;AACF,kBAAM,UAAU,cAAc,SAAS;AACvC,kBAAM,SAAS,cAAc,SAAS;AACtC,sBAAM,6BAAiB,KAAK,OAAO;AACnC,sBAAM,8BAAkB,KAAK,UAAU;AACvC,uBAAW,UAAM,mCAAuB,KAAK,MAAM,GAAG,GAAM;AAAA,UAC9D,SAAS,GAAG;AACV,gBAAI,KAAK,EAAE,GAAG,WAAW,GAAG,4BAA4B;AAAA,UAC1D;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,UAAI,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,GAAG,kCAAkC;AAAA,IACrE;AAAA,EACF;AAEA,MAAI,KAAK,yBAAyB;AACpC;", - "names": [] -} diff --git a/backend/dist/services/ssh.js b/backend/dist/services/ssh.js deleted file mode 100644 index 62dd600e..00000000 --- a/backend/dist/services/ssh.js +++ /dev/null @@ -1,115 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var ssh_exports = {}; -__export(ssh_exports, { - connectSsh: () => connectSsh -}); -module.exports = __toCommonJS(ssh_exports); -var import_ssh2 = require("ssh2"); -var import_logger = require("../lib/logger"); -const log = (0, import_logger.createLogger)("SSH"); -async function connectSsh(host, privateKey, maxWaitMs = 3e5) { - const start = Date.now(); - while (Date.now() - start < maxWaitMs) { - try { - const conn = await tryConnect(host, privateKey, 1e4); - let aborted = false; - return { - get aborted() { - return aborted; - }, - abort() { - aborted = true; - try { - conn.end(); - } catch { - } - }, - async exec(command) { - if (aborted) throw new Error("SSH session aborted"); - return execOnConn(conn, command); - }, - close() { - try { - conn.end(); - } catch { - } - } - }; - } catch (e) { - if (Date.now() - start > maxWaitMs) throw e; - log.debug({ host, error: e.message }, "SSH connect retry"); - await sleep(5e3); - } - } - throw new Error(`Could not SSH into ${host} within timeout`); -} -function tryConnect(host, privateKey, timeoutMs) { - return new Promise((resolve, reject) => { - const conn = new import_ssh2.Client(); - const timer = setTimeout(() => { - conn.end(); - reject(new Error(`SSH connection to ${host} timed out`)); - }, timeoutMs); - conn.on("ready", () => { - clearTimeout(timer); - resolve(conn); - }); - conn.on("error", (e) => { - clearTimeout(timer); - reject(e); - }); - conn.connect({ - host, - port: 22, - username: "ubuntu", - privateKey, - readyTimeout: timeoutMs, - algorithms: { - serverHostKey: ["ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521"] - } - }); - }); -} -function execOnConn(conn, command) { - return new Promise((resolve, reject) => { - conn.exec(command, (err, stream) => { - if (err) return reject(err); - let stdout = ""; - let stderr = ""; - stream.on("data", (d) => { - stdout += d.toString(); - }); - stream.stderr.on("data", (d) => { - stderr += d.toString(); - }); - stream.on("close", (code) => { - resolve({ stdout, stderr, code: code ?? 0 }); - }); - }); - }); -} -function sleep(ms) { - return new Promise((r) => setTimeout(r, ms)); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - connectSsh -}); -//# sourceMappingURL=ssh.js.map diff --git a/backend/dist/services/ssh.js.map b/backend/dist/services/ssh.js.map deleted file mode 100644 index b56d125f..00000000 --- a/backend/dist/services/ssh.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/services/ssh.ts"], - "sourcesContent": ["import { Client } from \"ssh2\";\nimport { createLogger } from \"../lib/logger\";\n\nconst log = createLogger(\"SSH\");\n\nexport interface SshSession {\n exec(command: string): Promise<{ stdout: string; stderr: string; code: number }>;\n close(): void;\n aborted: boolean;\n abort(): void;\n}\n\nexport async function connectSsh(host: string, privateKey: string, maxWaitMs = 300_000): Promise {\n const start = Date.now();\n\n while (Date.now() - start < maxWaitMs) {\n try {\n const conn = await tryConnect(host, privateKey, 10000);\n let aborted = false;\n\n return {\n get aborted() { return aborted; },\n abort() {\n aborted = true;\n try { conn.end(); } catch {}\n },\n async exec(command: string) {\n if (aborted) throw new Error(\"SSH session aborted\");\n return execOnConn(conn, command);\n },\n close() {\n try { conn.end(); } catch {}\n },\n };\n } catch (e: any) {\n if (Date.now() - start > maxWaitMs) throw e;\n log.debug({ host, error: e.message }, \"SSH connect retry\");\n await sleep(5000);\n }\n }\n throw new Error(`Could not SSH into ${host} within timeout`);\n}\n\nfunction tryConnect(host: string, privateKey: string, timeoutMs: number): Promise {\n return new Promise((resolve, reject) => {\n const conn = new Client();\n const timer = setTimeout(() => {\n conn.end();\n reject(new Error(`SSH connection to ${host} timed out`));\n }, timeoutMs);\n\n conn.on(\"ready\", () => {\n clearTimeout(timer);\n resolve(conn);\n });\n conn.on(\"error\", (e) => {\n clearTimeout(timer);\n reject(e);\n });\n conn.connect({\n host,\n port: 22,\n username: \"ubuntu\",\n privateKey,\n readyTimeout: timeoutMs,\n algorithms: {\n serverHostKey: [\"ssh-rsa\", \"ecdsa-sha2-nistp256\", \"ecdsa-sha2-nistp384\", \"ecdsa-sha2-nistp521\"],\n },\n });\n });\n}\n\nfunction execOnConn(conn: Client, command: string): Promise<{ stdout: string; stderr: string; code: number }> {\n return new Promise((resolve, reject) => {\n conn.exec(command, (err, stream) => {\n if (err) return reject(err);\n let stdout = \"\";\n let stderr = \"\";\n stream.on(\"data\", (d: Buffer) => { stdout += d.toString(); });\n stream.stderr.on(\"data\", (d: Buffer) => { stderr += d.toString(); });\n stream.on(\"close\", (code: number) => {\n resolve({ stdout, stderr, code: code ?? 0 });\n });\n });\n });\n}\n\nfunction sleep(ms: number) {\n return new Promise(r => setTimeout(r, ms));\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAuB;AACvB,oBAA6B;AAE7B,MAAM,UAAM,4BAAa,KAAK;AAS9B,eAAsB,WAAW,MAAc,YAAoB,YAAY,KAA8B;AAC3G,QAAM,QAAQ,KAAK,IAAI;AAEvB,SAAO,KAAK,IAAI,IAAI,QAAQ,WAAW;AACrC,QAAI;AACF,YAAM,OAAO,MAAM,WAAW,MAAM,YAAY,GAAK;AACrD,UAAI,UAAU;AAEd,aAAO;AAAA,QACL,IAAI,UAAU;AAAE,iBAAO;AAAA,QAAS;AAAA,QAChC,QAAQ;AACN,oBAAU;AACV,cAAI;AAAE,iBAAK,IAAI;AAAA,UAAG,QAAQ;AAAA,UAAC;AAAA,QAC7B;AAAA,QACA,MAAM,KAAK,SAAiB;AAC1B,cAAI,QAAS,OAAM,IAAI,MAAM,qBAAqB;AAClD,iBAAO,WAAW,MAAM,OAAO;AAAA,QACjC;AAAA,QACA,QAAQ;AACN,cAAI;AAAE,iBAAK,IAAI;AAAA,UAAG,QAAQ;AAAA,UAAC;AAAA,QAC7B;AAAA,MACF;AAAA,IACF,SAAS,GAAQ;AACf,UAAI,KAAK,IAAI,IAAI,QAAQ,UAAW,OAAM;AAC1C,UAAI,MAAM,EAAE,MAAM,OAAO,EAAE,QAAQ,GAAG,mBAAmB;AACzD,YAAM,MAAM,GAAI;AAAA,IAClB;AAAA,EACF;AACA,QAAM,IAAI,MAAM,sBAAsB,IAAI,iBAAiB;AAC7D;AAEA,SAAS,WAAW,MAAc,YAAoB,WAAoC;AACxF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,IAAI,mBAAO;AACxB,UAAM,QAAQ,WAAW,MAAM;AAC7B,WAAK,IAAI;AACT,aAAO,IAAI,MAAM,qBAAqB,IAAI,YAAY,CAAC;AAAA,IACzD,GAAG,SAAS;AAEZ,SAAK,GAAG,SAAS,MAAM;AACrB,mBAAa,KAAK;AAClB,cAAQ,IAAI;AAAA,IACd,CAAC;AACD,SAAK,GAAG,SAAS,CAAC,MAAM;AACtB,mBAAa,KAAK;AAClB,aAAO,CAAC;AAAA,IACV,CAAC;AACD,SAAK,QAAQ;AAAA,MACX;AAAA,MACA,MAAM;AAAA,MACN,UAAU;AAAA,MACV;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,QACV,eAAe,CAAC,WAAW,uBAAuB,uBAAuB,qBAAqB;AAAA,MAChG;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,WAAW,MAAc,SAA4E;AAC5G,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,SAAK,KAAK,SAAS,CAAC,KAAK,WAAW;AAClC,UAAI,IAAK,QAAO,OAAO,GAAG;AAC1B,UAAI,SAAS;AACb,UAAI,SAAS;AACb,aAAO,GAAG,QAAQ,CAAC,MAAc;AAAE,kBAAU,EAAE,SAAS;AAAA,MAAG,CAAC;AAC5D,aAAO,OAAO,GAAG,QAAQ,CAAC,MAAc;AAAE,kBAAU,EAAE,SAAS;AAAA,MAAG,CAAC;AACnE,aAAO,GAAG,SAAS,CAAC,SAAiB;AACnC,gBAAQ,EAAE,QAAQ,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,MAAM,IAAY;AACzB,SAAO,IAAI,QAAQ,OAAK,WAAW,GAAG,EAAE,CAAC;AAC3C;", - "names": [] -} diff --git a/backend/dist/workers/cronWorker.js b/backend/dist/workers/cronWorker.js deleted file mode 100644 index a44cb3b1..00000000 --- a/backend/dist/workers/cronWorker.js +++ /dev/null @@ -1,100 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var cronWorker_exports = {}; -__export(cronWorker_exports, { - startCronWorkers: () => startCronWorkers -}); -module.exports = __toCommonJS(cronWorker_exports); -var import_node_cron = __toESM(require("node-cron")); -var import_db = require("../lib/db"); -var import_logger = require("../lib/logger"); -var import_adminSettings = require("../lib/adminSettings"); -const log = (0, import_logger.createLogger)("CRON"); -function startCronWorkers() { - import_node_cron.default.schedule("*/30 * * * *", async () => { - try { - await checkInactivity(); - } catch (e) { - log.error({ e }, "Inactivity check error"); - } - }); - import_node_cron.default.schedule("0 3 * * *", async () => { - try { - await dailyCleanup(); - } catch (e) { - log.error({ e }, "Daily cleanup error"); - } - }); - log.info("Cron workers started"); -} -async function checkInactivity() { - const settings = await (0, import_adminSettings.getAdminSettings)(); - const now = /* @__PURE__ */ new Date(); - const running = await import_db.prisma.preview.findMany({ - where: { status: "RUNNING" } - }); - for (const preview of running) { - const inactivityMs = settings.maxConcurrentInstancesPerUser; - const repoConfig = await import_db.prisma.repoConfig.findUnique({ where: { id: preview.repoConfigId } }); - if (!repoConfig) continue; - const deadline = new Date(preview.lastActivityAt.getTime() + repoConfig.inactivityHours * 3600 * 1e3); - if (now >= deadline) { - log.info({ previewId: preview.id }, "Preview inactive, enqueuing INACTIVITY_STOP"); - await import_db.prisma.job.create({ - data: { - previewId: preview.id, - type: "INACTIVITY_STOP", - status: "PENDING", - payload: {} - } - }); - } - } -} -async function dailyCleanup() { - const settings = await (0, import_adminSettings.getAdminSettings)(); - const cutoff = new Date(Date.now() - settings.previewRetentionDays * 86400 * 1e3); - const old = await import_db.prisma.preview.findMany({ - where: { - status: { in: ["STOPPED", "FAILED"] }, - stoppedAt: { lt: cutoff } - }, - select: { id: true } - }); - for (const { id } of old) { - await import_db.prisma.job.deleteMany({ where: { previewId: id } }); - await import_db.prisma.preview.delete({ where: { id } }); - } - if (old.length > 0) log.info({ count: old.length }, "Cleaned up old previews"); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - startCronWorkers -}); -//# sourceMappingURL=cronWorker.js.map diff --git a/backend/dist/workers/cronWorker.js.map b/backend/dist/workers/cronWorker.js.map deleted file mode 100644 index 104be027..00000000 --- a/backend/dist/workers/cronWorker.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/workers/cronWorker.ts"], - "sourcesContent": ["import cron from \"node-cron\";\nimport { prisma } from \"../lib/db\";\nimport { createLogger } from \"../lib/logger\";\nimport { getAdminSettings } from \"../lib/adminSettings\";\n\nconst log = createLogger(\"CRON\");\n\nexport function startCronWorkers() {\n // Inactivity check every 30 minutes\n cron.schedule(\"*/30 * * * *\", async () => {\n try {\n await checkInactivity();\n } catch (e) {\n log.error({ e }, \"Inactivity check error\");\n }\n });\n\n // Daily cleanup\n cron.schedule(\"0 3 * * *\", async () => {\n try {\n await dailyCleanup();\n } catch (e) {\n log.error({ e }, \"Daily cleanup error\");\n }\n });\n\n log.info(\"Cron workers started\");\n}\n\nasync function checkInactivity() {\n const settings = await getAdminSettings();\n const now = new Date();\n\n const running = await prisma.preview.findMany({\n where: { status: \"RUNNING\" },\n });\n\n for (const preview of running) {\n const inactivityMs = settings.maxConcurrentInstancesPerUser; // will use actual inactivityHours from repoConfig\n const repoConfig = await prisma.repoConfig.findUnique({ where: { id: preview.repoConfigId } });\n if (!repoConfig) continue;\n\n const deadline = new Date(preview.lastActivityAt.getTime() + repoConfig.inactivityHours * 3600 * 1000);\n if (now >= deadline) {\n log.info({ previewId: preview.id }, \"Preview inactive, enqueuing INACTIVITY_STOP\");\n await prisma.job.create({\n data: {\n previewId: preview.id,\n type: \"INACTIVITY_STOP\",\n status: \"PENDING\",\n payload: {},\n },\n });\n }\n }\n}\n\nasync function dailyCleanup() {\n const settings = await getAdminSettings();\n const cutoff = new Date(Date.now() - settings.previewRetentionDays * 86400 * 1000);\n\n const old = await prisma.preview.findMany({\n where: {\n status: { in: [\"STOPPED\", \"FAILED\"] },\n stoppedAt: { lt: cutoff },\n },\n select: { id: true },\n });\n\n for (const { id } of old) {\n await prisma.job.deleteMany({ where: { previewId: id } });\n await prisma.preview.delete({ where: { id } });\n }\n\n if (old.length > 0) log.info({ count: old.length }, \"Cleaned up old previews\");\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AACjB,gBAAuB;AACvB,oBAA6B;AAC7B,2BAAiC;AAEjC,MAAM,UAAM,4BAAa,MAAM;AAExB,SAAS,mBAAmB;AAEjC,mBAAAA,QAAK,SAAS,gBAAgB,YAAY;AACxC,QAAI;AACF,YAAM,gBAAgB;AAAA,IACxB,SAAS,GAAG;AACV,UAAI,MAAM,EAAE,EAAE,GAAG,wBAAwB;AAAA,IAC3C;AAAA,EACF,CAAC;AAGD,mBAAAA,QAAK,SAAS,aAAa,YAAY;AACrC,QAAI;AACF,YAAM,aAAa;AAAA,IACrB,SAAS,GAAG;AACV,UAAI,MAAM,EAAE,EAAE,GAAG,qBAAqB;AAAA,IACxC;AAAA,EACF,CAAC;AAED,MAAI,KAAK,sBAAsB;AACjC;AAEA,eAAe,kBAAkB;AAC/B,QAAM,WAAW,UAAM,uCAAiB;AACxC,QAAM,MAAM,oBAAI,KAAK;AAErB,QAAM,UAAU,MAAM,iBAAO,QAAQ,SAAS;AAAA,IAC5C,OAAO,EAAE,QAAQ,UAAU;AAAA,EAC7B,CAAC;AAED,aAAW,WAAW,SAAS;AAC7B,UAAM,eAAe,SAAS;AAC9B,UAAM,aAAa,MAAM,iBAAO,WAAW,WAAW,EAAE,OAAO,EAAE,IAAI,QAAQ,aAAa,EAAE,CAAC;AAC7F,QAAI,CAAC,WAAY;AAEjB,UAAM,WAAW,IAAI,KAAK,QAAQ,eAAe,QAAQ,IAAI,WAAW,kBAAkB,OAAO,GAAI;AACrG,QAAI,OAAO,UAAU;AACnB,UAAI,KAAK,EAAE,WAAW,QAAQ,GAAG,GAAG,6CAA6C;AACjF,YAAM,iBAAO,IAAI,OAAO;AAAA,QACtB,MAAM;AAAA,UACJ,WAAW,QAAQ;AAAA,UACnB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,SAAS,CAAC;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,eAAe;AAC5B,QAAM,WAAW,UAAM,uCAAiB;AACxC,QAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,uBAAuB,QAAQ,GAAI;AAEjF,QAAM,MAAM,MAAM,iBAAO,QAAQ,SAAS;AAAA,IACxC,OAAO;AAAA,MACL,QAAQ,EAAE,IAAI,CAAC,WAAW,QAAQ,EAAE;AAAA,MACpC,WAAW,EAAE,IAAI,OAAO;AAAA,IAC1B;AAAA,IACA,QAAQ,EAAE,IAAI,KAAK;AAAA,EACrB,CAAC;AAED,aAAW,EAAE,GAAG,KAAK,KAAK;AACxB,UAAM,iBAAO,IAAI,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,EAAE,CAAC;AACxD,UAAM,iBAAO,QAAQ,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAAA,EAC/C;AAEA,MAAI,IAAI,SAAS,EAAG,KAAI,KAAK,EAAE,OAAO,IAAI,OAAO,GAAG,yBAAyB;AAC/E;", - "names": ["cron"] -} diff --git a/backend/dist/workers/jobWorker.js b/backend/dist/workers/jobWorker.js deleted file mode 100644 index 2497293f..00000000 --- a/backend/dist/workers/jobWorker.js +++ /dev/null @@ -1,114 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); -var jobWorker_exports = {}; -__export(jobWorker_exports, { - startJobWorker: () => startJobWorker, - stopJobWorker: () => stopJobWorker -}); -module.exports = __toCommonJS(jobWorker_exports); -var import_db = require("../lib/db"); -var import_logger = require("../lib/logger"); -var import_deploy = require("../services/deploy"); -const log = (0, import_logger.createLogger)("JOB_WORKER"); -let running = false; -async function startJobWorker() { - if (running) return; - running = true; - log.info("Job worker started"); - await resetStuckJobs(); - pollLoop(); -} -async function resetStuckJobs() { - const count = await import_db.prisma.job.updateMany({ - where: { status: "RUNNING" }, - data: { status: "PENDING", startedAt: null } - }); - if (count.count > 0) log.info({ count: count.count }, "Reset stuck running jobs to PENDING"); -} -async function pollLoop() { - while (running) { - try { - await processPendingJobs(); - } catch (e) { - log.error({ e }, "Job worker poll error"); - } - await sleep(1e3); - } -} -const activePreviewJobs = /* @__PURE__ */ new Map(); -async function processPendingJobs() { - const pending = await import_db.prisma.job.findMany({ - where: { status: "PENDING" }, - orderBy: { createdAt: "asc" }, - take: 20 - }); - for (const job of pending) { - const previewId = job.previewId; - if (!previewId) continue; - if (activePreviewJobs.has(previewId)) { - const existingJobId = activePreviewJobs.get(previewId); - if (job.type === "DEPLOY") { - log.info({ previewId, newJobId: job.id, abortingJobId: existingJobId }, "New deploy cancels existing"); - (0, import_deploy.signalAbort)(previewId); - await sleep(500); - } else { - continue; - } - } - activePreviewJobs.set(previewId, job.id); - processJob(job).finally(() => { - if (activePreviewJobs.get(previewId) === job.id) { - activePreviewJobs.delete(previewId); - } - }); - } -} -async function processJob(job) { - log.info({ jobId: job.id, type: job.type, previewId: job.previewId }, "Processing job"); - try { - if (job.type === "DEPLOY") { - await (0, import_deploy.runDeploy)(job.id); - } else if (job.type === "STOP" || job.type === "INACTIVITY_STOP") { - if (job.previewId) { - await import_db.prisma.job.update({ where: { id: job.id }, data: { status: "RUNNING", startedAt: /* @__PURE__ */ new Date() } }); - await (0, import_deploy.stopPreview)(job.previewId); - await import_db.prisma.job.update({ where: { id: job.id }, data: { status: "DONE", finishedAt: /* @__PURE__ */ new Date() } }); - } - } - } catch (e) { - log.error({ e, jobId: job.id }, "Job processing error"); - await import_db.prisma.job.update({ - where: { id: job.id }, - data: { status: "FAILED", error: e.message, finishedAt: /* @__PURE__ */ new Date() } - }).catch(() => { - }); - } -} -function stopJobWorker() { - running = false; -} -function sleep(ms) { - return new Promise((r) => setTimeout(r, ms)); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - startJobWorker, - stopJobWorker -}); -//# sourceMappingURL=jobWorker.js.map diff --git a/backend/dist/workers/jobWorker.js.map b/backend/dist/workers/jobWorker.js.map deleted file mode 100644 index 85db799c..00000000 --- a/backend/dist/workers/jobWorker.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../src/workers/jobWorker.ts"], - "sourcesContent": ["import { prisma } from \"../lib/db\";\nimport { createLogger } from \"../lib/logger\";\nimport { runDeploy, stopPreview, signalAbort } from \"../services/deploy\";\n\nconst log = createLogger(\"JOB_WORKER\");\nlet running = false;\n\nexport async function startJobWorker() {\n if (running) return;\n running = true;\n log.info(\"Job worker started\");\n\n await resetStuckJobs();\n pollLoop();\n}\n\nasync function resetStuckJobs() {\n const count = await prisma.job.updateMany({\n where: { status: \"RUNNING\" },\n data: { status: \"PENDING\", startedAt: null },\n });\n if (count.count > 0) log.info({ count: count.count }, \"Reset stuck running jobs to PENDING\");\n}\n\nasync function pollLoop() {\n while (running) {\n try {\n await processPendingJobs();\n } catch (e) {\n log.error({ e }, \"Job worker poll error\");\n }\n await sleep(1000);\n }\n}\n\nconst activePreviewJobs = new Map();\n\nasync function processPendingJobs() {\n const pending = await prisma.job.findMany({\n where: { status: \"PENDING\" },\n orderBy: { createdAt: \"asc\" },\n take: 20,\n });\n\n for (const job of pending) {\n const previewId = job.previewId;\n if (!previewId) continue;\n\n if (activePreviewJobs.has(previewId)) {\n const existingJobId = activePreviewJobs.get(previewId)!;\n\n if (job.type === \"DEPLOY\") {\n log.info({ previewId, newJobId: job.id, abortingJobId: existingJobId }, \"New deploy cancels existing\");\n signalAbort(previewId);\n await sleep(500);\n } else {\n continue;\n }\n }\n\n activePreviewJobs.set(previewId, job.id);\n\n processJob(job).finally(() => {\n if (activePreviewJobs.get(previewId) === job.id) {\n activePreviewJobs.delete(previewId);\n }\n });\n }\n}\n\nasync function processJob(job: { id: number; type: string; previewId: number | null; payload: any }) {\n log.info({ jobId: job.id, type: job.type, previewId: job.previewId }, \"Processing job\");\n\n try {\n if (job.type === \"DEPLOY\") {\n await runDeploy(job.id);\n } else if (job.type === \"STOP\" || job.type === \"INACTIVITY_STOP\") {\n if (job.previewId) {\n await prisma.job.update({ where: { id: job.id }, data: { status: \"RUNNING\", startedAt: new Date() } });\n await stopPreview(job.previewId);\n await prisma.job.update({ where: { id: job.id }, data: { status: \"DONE\", finishedAt: new Date() } });\n }\n }\n } catch (e: any) {\n log.error({ e, jobId: job.id }, \"Job processing error\");\n await prisma.job.update({\n where: { id: job.id },\n data: { status: \"FAILED\", error: e.message, finishedAt: new Date() },\n }).catch(() => {});\n }\n}\n\nexport function stopJobWorker() {\n running = false;\n}\n\nfunction sleep(ms: number) {\n return new Promise(r => setTimeout(r, ms));\n}\n"], - "mappings": "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", - "names": [] -} diff --git a/frontend/dist/assets/index-BhM-WgUO.js b/frontend/dist/assets/index-BhM-WgUO.js deleted file mode 100644 index 080891ea..00000000 --- a/frontend/dist/assets/index-BhM-WgUO.js +++ /dev/null @@ -1,905 +0,0 @@ -(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))r(u);new MutationObserver(u=>{for(const d of u)if(d.type==="childList")for(const f of d.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&r(f)}).observe(document,{childList:!0,subtree:!0});function l(u){const d={};return u.integrity&&(d.integrity=u.integrity),u.referrerPolicy&&(d.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?d.credentials="include":u.crossOrigin==="anonymous"?d.credentials="omit":d.credentials="same-origin",d}function r(u){if(u.ep)return;u.ep=!0;const d=l(u);fetch(u.href,d)}})();function mg(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}var zc={exports:{}},Ls={};/** - * @license React - * react-jsx-runtime.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Cy;function J1(){if(Cy)return Ls;Cy=1;var n=Symbol.for("react.transitional.element"),i=Symbol.for("react.fragment");function l(r,u,d){var f=null;if(d!==void 0&&(f=""+d),u.key!==void 0&&(f=""+u.key),"key"in u){d={};for(var h in u)h!=="key"&&(d[h]=u[h])}else d=u;return u=d.ref,{$$typeof:n,type:r,key:f,ref:u!==void 0?u:null,props:d}}return Ls.Fragment=i,Ls.jsx=l,Ls.jsxs=l,Ls}var wy;function W1(){return wy||(wy=1,zc.exports=J1()),zc.exports}var g=W1(),Lc={exports:{}},ft={};/** - * @license React - * react.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Ry;function I1(){if(Ry)return ft;Ry=1;var n=Symbol.for("react.transitional.element"),i=Symbol.for("react.portal"),l=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),u=Symbol.for("react.profiler"),d=Symbol.for("react.consumer"),f=Symbol.for("react.context"),h=Symbol.for("react.forward_ref"),m=Symbol.for("react.suspense"),p=Symbol.for("react.memo"),v=Symbol.for("react.lazy"),x=Symbol.for("react.activity"),S=Symbol.iterator;function E(N){return N===null||typeof N!="object"?null:(N=S&&N[S]||N["@@iterator"],typeof N=="function"?N:null)}var A={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},w=Object.assign,_={};function R(N,K,et){this.props=N,this.context=K,this.refs=_,this.updater=et||A}R.prototype.isReactComponent={},R.prototype.setState=function(N,K){if(typeof N!="object"&&typeof N!="function"&&N!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,N,K,"setState")},R.prototype.forceUpdate=function(N){this.updater.enqueueForceUpdate(this,N,"forceUpdate")};function O(){}O.prototype=R.prototype;function D(N,K,et){this.props=N,this.context=K,this.refs=_,this.updater=et||A}var M=D.prototype=new O;M.constructor=D,w(M,R.prototype),M.isPureReactComponent=!0;var H=Array.isArray;function $(){}var V={H:null,A:null,T:null,S:null},q=Object.prototype.hasOwnProperty;function Z(N,K,et){var it=et.ref;return{$$typeof:n,type:N,key:K,ref:it!==void 0?it:null,props:et}}function F(N,K){return Z(N.type,K,N.props)}function I(N){return typeof N=="object"&&N!==null&&N.$$typeof===n}function ut(N){var K={"=":"=0",":":"=2"};return"$"+N.replace(/[=:]/g,function(et){return K[et]})}var Tt=/\/+/g;function pt(N,K){return typeof N=="object"&&N!==null&&N.key!=null?ut(""+N.key):K.toString(36)}function Q(N){switch(N.status){case"fulfilled":return N.value;case"rejected":throw N.reason;default:switch(typeof N.status=="string"?N.then($,$):(N.status="pending",N.then(function(K){N.status==="pending"&&(N.status="fulfilled",N.value=K)},function(K){N.status==="pending"&&(N.status="rejected",N.reason=K)})),N.status){case"fulfilled":return N.value;case"rejected":throw N.reason}}throw N}function L(N,K,et,it,dt){var yt=typeof N;(yt==="undefined"||yt==="boolean")&&(N=null);var wt=!1;if(N===null)wt=!0;else switch(yt){case"bigint":case"string":case"number":wt=!0;break;case"object":switch(N.$$typeof){case n:case i:wt=!0;break;case v:return wt=N._init,L(wt(N._payload),K,et,it,dt)}}if(wt)return dt=dt(N),wt=it===""?"."+pt(N,0):it,H(dt)?(et="",wt!=null&&(et=wt.replace(Tt,"$&/")+"/"),L(dt,K,et,"",function(Yi){return Yi})):dt!=null&&(I(dt)&&(dt=F(dt,et+(dt.key==null||N&&N.key===dt.key?"":(""+dt.key).replace(Tt,"$&/")+"/")+wt)),K.push(dt)),1;wt=0;var fe=it===""?".":it+":";if(H(N))for(var Xt=0;Xt>>1,ct=L[W];if(0>>1;Wu(et,tt))itu(dt,et)?(L[W]=dt,L[it]=tt,W=it):(L[W]=et,L[K]=tt,W=K);else if(itu(dt,tt))L[W]=dt,L[it]=tt,W=it;else break t}}return J}function u(L,J){var tt=L.sortIndex-J.sortIndex;return tt!==0?tt:L.id-J.id}if(n.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var d=performance;n.unstable_now=function(){return d.now()}}else{var f=Date,h=f.now();n.unstable_now=function(){return f.now()-h}}var m=[],p=[],v=1,x=null,S=3,E=!1,A=!1,w=!1,_=!1,R=typeof setTimeout=="function"?setTimeout:null,O=typeof clearTimeout=="function"?clearTimeout:null,D=typeof setImmediate<"u"?setImmediate:null;function M(L){for(var J=l(p);J!==null;){if(J.callback===null)r(p);else if(J.startTime<=L)r(p),J.sortIndex=J.expirationTime,i(m,J);else break;J=l(p)}}function H(L){if(w=!1,M(L),!A)if(l(m)!==null)A=!0,$||($=!0,ut());else{var J=l(p);J!==null&&Q(H,J.startTime-L)}}var $=!1,V=-1,q=5,Z=-1;function F(){return _?!0:!(n.unstable_now()-ZL&&F());){var W=x.callback;if(typeof W=="function"){x.callback=null,S=x.priorityLevel;var ct=W(x.expirationTime<=L);if(L=n.unstable_now(),typeof ct=="function"){x.callback=ct,M(L),J=!0;break e}x===l(m)&&r(m),M(L)}else r(m);x=l(m)}if(x!==null)J=!0;else{var N=l(p);N!==null&&Q(H,N.startTime-L),J=!1}}break t}finally{x=null,S=tt,E=!1}J=void 0}}finally{J?ut():$=!1}}}var ut;if(typeof D=="function")ut=function(){D(I)};else if(typeof MessageChannel<"u"){var Tt=new MessageChannel,pt=Tt.port2;Tt.port1.onmessage=I,ut=function(){pt.postMessage(null)}}else ut=function(){R(I,0)};function Q(L,J){V=R(function(){L(n.unstable_now())},J)}n.unstable_IdlePriority=5,n.unstable_ImmediatePriority=1,n.unstable_LowPriority=4,n.unstable_NormalPriority=3,n.unstable_Profiling=null,n.unstable_UserBlockingPriority=2,n.unstable_cancelCallback=function(L){L.callback=null},n.unstable_forceFrameRate=function(L){0>L||125W?(L.sortIndex=tt,i(p,L),l(m)===null&&L===l(p)&&(w?(O(V),V=-1):w=!0,Q(H,tt-W))):(L.sortIndex=ct,i(m,L),A||E||(A=!0,$||($=!0,ut()))),L},n.unstable_shouldYield=F,n.unstable_wrapCallback=function(L){var J=S;return function(){var tt=S;S=J;try{return L.apply(this,arguments)}finally{S=tt}}}})(Vc)),Vc}var jy;function eS(){return jy||(jy=1,Uc.exports=tS()),Uc.exports}var Bc={exports:{}},ce={};/** - * @license React - * react-dom.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Dy;function nS(){if(Dy)return ce;Dy=1;var n=Vf();function i(m){var p="https://react.dev/errors/"+m;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(i){console.error(i)}}return n(),Bc.exports=nS(),Bc.exports}/** - * @license React - * react-dom-client.production.js - * - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Oy;function iS(){if(Oy)return ks;Oy=1;var n=eS(),i=Vf(),l=aS();function r(t){var e="https://react.dev/errors/"+t;if(1ct||(t.current=W[ct],W[ct]=null,ct--)}function et(t,e){ct++,W[ct]=t.current,t.current=e}var it=N(null),dt=N(null),yt=N(null),wt=N(null);function fe(t,e){switch(et(yt,e),et(dt,t),et(it,null),e.nodeType){case 9:case 11:t=(t=e.documentElement)&&(t=t.namespaceURI)?Zp(t):0;break;default:if(t=e.tagName,e=e.namespaceURI)e=Zp(e),t=$p(e,t);else switch(t){case"svg":t=1;break;case"math":t=2;break;default:t=0}}K(it),et(it,t)}function Xt(){K(it),K(dt),K(yt)}function Yi(t){t.memoizedState!==null&&et(wt,t);var e=it.current,a=$p(e,t.type);e!==a&&(et(dt,t),et(it,a))}function rl(t){dt.current===t&&(K(it),K(dt)),wt.current===t&&(K(wt),Ds._currentValue=tt)}var yo,Ad;function ga(t){if(yo===void 0)try{throw Error()}catch(a){var e=a.stack.trim().match(/\n( *(at )?)/);yo=e&&e[1]||"",Ad=-1)":-1o||C[s]!==U[o]){var Y=` -`+C[s].replace(" at new "," at ");return t.displayName&&Y.includes("")&&(Y=Y.replace("",t.displayName)),Y}while(1<=s&&0<=o);break}}}finally{go=!1,Error.prepareStackTrace=a}return(a=t?t.displayName||t.name:"")?ga(a):""}function _x(t,e){switch(t.tag){case 26:case 27:case 5:return ga(t.type);case 16:return ga("Lazy");case 13:return t.child!==e&&e!==null?ga("Suspense Fallback"):ga("Suspense");case 19:return ga("SuspenseList");case 0:case 15:return vo(t.type,!1);case 11:return vo(t.type.render,!1);case 1:return vo(t.type,!0);case 31:return ga("Activity");default:return""}}function Cd(t){try{var e="",a=null;do e+=_x(t,a),a=t,t=t.return;while(t);return e}catch(s){return` -Error generating stack: `+s.message+` -`+s.stack}}var xo=Object.prototype.hasOwnProperty,bo=n.unstable_scheduleCallback,So=n.unstable_cancelCallback,Nx=n.unstable_shouldYield,jx=n.unstable_requestPaint,Ee=n.unstable_now,Dx=n.unstable_getCurrentPriorityLevel,wd=n.unstable_ImmediatePriority,Rd=n.unstable_UserBlockingPriority,ol=n.unstable_NormalPriority,Mx=n.unstable_LowPriority,_d=n.unstable_IdlePriority,Ox=n.log,zx=n.unstable_setDisableYieldValue,qi=null,Ae=null;function Vn(t){if(typeof Ox=="function"&&zx(t),Ae&&typeof Ae.setStrictMode=="function")try{Ae.setStrictMode(qi,t)}catch{}}var Ce=Math.clz32?Math.clz32:Ux,Lx=Math.log,kx=Math.LN2;function Ux(t){return t>>>=0,t===0?32:31-(Lx(t)/kx|0)|0}var ul=256,cl=262144,fl=4194304;function va(t){var e=t&42;if(e!==0)return e;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&261888;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function dl(t,e,a){var s=t.pendingLanes;if(s===0)return 0;var o=0,c=t.suspendedLanes,y=t.pingedLanes;t=t.warmLanes;var b=s&134217727;return b!==0?(s=b&~c,s!==0?o=va(s):(y&=b,y!==0?o=va(y):a||(a=b&~t,a!==0&&(o=va(a))))):(b=s&~c,b!==0?o=va(b):y!==0?o=va(y):a||(a=s&~t,a!==0&&(o=va(a)))),o===0?0:e!==0&&e!==o&&(e&c)===0&&(c=o&-o,a=e&-e,c>=a||c===32&&(a&4194048)!==0)?e:o}function Pi(t,e){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&e)===0}function Vx(t,e){switch(t){case 1:case 2:case 4:case 8:case 64:return e+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Nd(){var t=fl;return fl<<=1,(fl&62914560)===0&&(fl=4194304),t}function To(t){for(var e=[],a=0;31>a;a++)e.push(t);return e}function Xi(t,e){t.pendingLanes|=e,e!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function Bx(t,e,a,s,o,c){var y=t.pendingLanes;t.pendingLanes=a,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=a,t.entangledLanes&=a,t.errorRecoveryDisabledLanes&=a,t.shellSuspendCounter=0;var b=t.entanglements,C=t.expirationTimes,U=t.hiddenUpdates;for(a=y&~a;0"u")return null;try{return t.activeElement||t.body}catch{return t.body}}var Xx=/[\n"\\]/g;function ke(t){return t.replace(Xx,function(e){return"\\"+e.charCodeAt(0).toString(16)+" "})}function _o(t,e,a,s,o,c,y,b){t.name="",y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"?t.type=y:t.removeAttribute("type"),e!=null?y==="number"?(e===0&&t.value===""||t.value!=e)&&(t.value=""+Le(e)):t.value!==""+Le(e)&&(t.value=""+Le(e)):y!=="submit"&&y!=="reset"||t.removeAttribute("value"),e!=null?No(t,y,Le(e)):a!=null?No(t,y,Le(a)):s!=null&&t.removeAttribute("value"),o==null&&c!=null&&(t.defaultChecked=!!c),o!=null&&(t.checked=o&&typeof o!="function"&&typeof o!="symbol"),b!=null&&typeof b!="function"&&typeof b!="symbol"&&typeof b!="boolean"?t.name=""+Le(b):t.removeAttribute("name")}function Yd(t,e,a,s,o,c,y,b){if(c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(t.type=c),e!=null||a!=null){if(!(c!=="submit"&&c!=="reset"||e!=null)){Ro(t);return}a=a!=null?""+Le(a):"",e=e!=null?""+Le(e):a,b||e===t.value||(t.value=e),t.defaultValue=e}s=s??o,s=typeof s!="function"&&typeof s!="symbol"&&!!s,t.checked=b?t.checked:!!s,t.defaultChecked=!!s,y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"&&(t.name=y),Ro(t)}function No(t,e,a){e==="number"&&pl(t.ownerDocument)===t||t.defaultValue===""+a||(t.defaultValue=""+a)}function $a(t,e,a,s){if(t=t.options,e){e={};for(var o=0;o"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),zo=!1;if(vn)try{var $i={};Object.defineProperty($i,"passive",{get:function(){zo=!0}}),window.addEventListener("test",$i,$i),window.removeEventListener("test",$i,$i)}catch{zo=!1}var Hn=null,Lo=null,gl=null;function $d(){if(gl)return gl;var t,e=Lo,a=e.length,s,o="value"in Hn?Hn.value:Hn.textContent,c=o.length;for(t=0;t=Wi),eh=" ",nh=!1;function ah(t,e){switch(t){case"keyup":return xb.indexOf(e.keyCode)!==-1;case"keydown":return e.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function ih(t){return t=t.detail,typeof t=="object"&&"data"in t?t.data:null}var Ia=!1;function Sb(t,e){switch(t){case"compositionend":return ih(e);case"keypress":return e.which!==32?null:(nh=!0,eh);case"textInput":return t=e.data,t===eh&&nh?null:t;default:return null}}function Tb(t,e){if(Ia)return t==="compositionend"||!Ho&&ah(t,e)?(t=$d(),gl=Lo=Hn=null,Ia=!1,t):null;switch(t){case"paste":return null;case"keypress":if(!(e.ctrlKey||e.altKey||e.metaKey)||e.ctrlKey&&e.altKey){if(e.char&&1=e)return{node:a,offset:e-t};t=s}t:{for(;a;){if(a.nextSibling){a=a.nextSibling;break t}a=a.parentNode}a=void 0}a=dh(a)}}function mh(t,e){return t&&e?t===e?!0:t&&t.nodeType===3?!1:e&&e.nodeType===3?mh(t,e.parentNode):"contains"in t?t.contains(e):t.compareDocumentPosition?!!(t.compareDocumentPosition(e)&16):!1:!1}function ph(t){t=t!=null&&t.ownerDocument!=null&&t.ownerDocument.defaultView!=null?t.ownerDocument.defaultView:window;for(var e=pl(t.document);e instanceof t.HTMLIFrameElement;){try{var a=typeof e.contentWindow.location.href=="string"}catch{a=!1}if(a)t=e.contentWindow;else break;e=pl(t.document)}return e}function qo(t){var e=t&&t.nodeName&&t.nodeName.toLowerCase();return e&&(e==="input"&&(t.type==="text"||t.type==="search"||t.type==="tel"||t.type==="url"||t.type==="password")||e==="textarea"||t.contentEditable==="true")}var jb=vn&&"documentMode"in document&&11>=document.documentMode,ti=null,Po=null,ns=null,Xo=!1;function yh(t,e,a){var s=a.window===a?a.document:a.nodeType===9?a:a.ownerDocument;Xo||ti==null||ti!==pl(s)||(s=ti,"selectionStart"in s&&qo(s)?s={start:s.selectionStart,end:s.selectionEnd}:(s=(s.ownerDocument&&s.ownerDocument.defaultView||window).getSelection(),s={anchorNode:s.anchorNode,anchorOffset:s.anchorOffset,focusNode:s.focusNode,focusOffset:s.focusOffset}),ns&&es(ns,s)||(ns=s,s=cr(Po,"onSelect"),0>=y,o-=y,rn=1<<32-Ce(e)+o|a<mt?(bt=st,st=null):bt=st.sibling;var At=B(z,st,k[mt],P);if(At===null){st===null&&(st=bt);break}t&&st&&At.alternate===null&&e(z,st),j=c(At,j,mt),Et===null?rt=At:Et.sibling=At,Et=At,st=bt}if(mt===k.length)return a(z,st),St&&bn(z,mt),rt;if(st===null){for(;mtmt?(bt=st,st=null):bt=st.sibling;var oa=B(z,st,At.value,P);if(oa===null){st===null&&(st=bt);break}t&&st&&oa.alternate===null&&e(z,st),j=c(oa,j,mt),Et===null?rt=oa:Et.sibling=oa,Et=oa,st=bt}if(At.done)return a(z,st),St&&bn(z,mt),rt;if(st===null){for(;!At.done;mt++,At=k.next())At=X(z,At.value,P),At!==null&&(j=c(At,j,mt),Et===null?rt=At:Et.sibling=At,Et=At);return St&&bn(z,mt),rt}for(st=s(st);!At.done;mt++,At=k.next())At=G(st,z,mt,At.value,P),At!==null&&(t&&At.alternate!==null&&st.delete(At.key===null?mt:At.key),j=c(At,j,mt),Et===null?rt=At:Et.sibling=At,Et=At);return t&&st.forEach(function(F1){return e(z,F1)}),St&&bn(z,mt),rt}function Ot(z,j,k,P){if(typeof k=="object"&&k!==null&&k.type===w&&k.key===null&&(k=k.props.children),typeof k=="object"&&k!==null){switch(k.$$typeof){case E:t:{for(var rt=k.key;j!==null;){if(j.key===rt){if(rt=k.type,rt===w){if(j.tag===7){a(z,j.sibling),P=o(j,k.props.children),P.return=z,z=P;break t}}else if(j.elementType===rt||typeof rt=="object"&&rt!==null&&rt.$$typeof===q&&Na(rt)===j.type){a(z,j.sibling),P=o(j,k.props),os(P,k),P.return=z,z=P;break t}a(z,j);break}else e(z,j);j=j.sibling}k.type===w?(P=Aa(k.props.children,z.mode,P,k.key),P.return=z,z=P):(P=Rl(k.type,k.key,k.props,null,z.mode,P),os(P,k),P.return=z,z=P)}return y(z);case A:t:{for(rt=k.key;j!==null;){if(j.key===rt)if(j.tag===4&&j.stateNode.containerInfo===k.containerInfo&&j.stateNode.implementation===k.implementation){a(z,j.sibling),P=o(j,k.children||[]),P.return=z,z=P;break t}else{a(z,j);break}else e(z,j);j=j.sibling}P=Wo(k,z.mode,P),P.return=z,z=P}return y(z);case q:return k=Na(k),Ot(z,j,k,P)}if(Q(k))return nt(z,j,k,P);if(ut(k)){if(rt=ut(k),typeof rt!="function")throw Error(r(150));return k=rt.call(k),ot(z,j,k,P)}if(typeof k.then=="function")return Ot(z,j,zl(k),P);if(k.$$typeof===D)return Ot(z,j,jl(z,k),P);Ll(z,k)}return typeof k=="string"&&k!==""||typeof k=="number"||typeof k=="bigint"?(k=""+k,j!==null&&j.tag===6?(a(z,j.sibling),P=o(j,k),P.return=z,z=P):(a(z,j),P=Jo(k,z.mode,P),P.return=z,z=P),y(z)):a(z,j)}return function(z,j,k,P){try{rs=0;var rt=Ot(z,j,k,P);return fi=null,rt}catch(st){if(st===ci||st===Ml)throw st;var Et=Re(29,st,null,z.mode);return Et.lanes=P,Et.return=z,Et}finally{}}}var Da=Bh(!0),Hh=Bh(!1),Xn=!1;function cu(t){t.updateQueue={baseState:t.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function fu(t,e){t=t.updateQueue,e.updateQueue===t&&(e.updateQueue={baseState:t.baseState,firstBaseUpdate:t.firstBaseUpdate,lastBaseUpdate:t.lastBaseUpdate,shared:t.shared,callbacks:null})}function Kn(t){return{lane:t,tag:0,payload:null,callback:null,next:null}}function Qn(t,e,a){var s=t.updateQueue;if(s===null)return null;if(s=s.shared,(Ct&2)!==0){var o=s.pending;return o===null?e.next=e:(e.next=o.next,o.next=e),s.pending=e,e=wl(t),Eh(t,null,a),e}return Cl(t,s,e,a),wl(t)}function us(t,e,a){if(e=e.updateQueue,e!==null&&(e=e.shared,(a&4194048)!==0)){var s=e.lanes;s&=t.pendingLanes,a|=s,e.lanes=a,Dd(t,a)}}function du(t,e){var a=t.updateQueue,s=t.alternate;if(s!==null&&(s=s.updateQueue,a===s)){var o=null,c=null;if(a=a.firstBaseUpdate,a!==null){do{var y={lane:a.lane,tag:a.tag,payload:a.payload,callback:null,next:null};c===null?o=c=y:c=c.next=y,a=a.next}while(a!==null);c===null?o=c=e:c=c.next=e}else o=c=e;a={baseState:s.baseState,firstBaseUpdate:o,lastBaseUpdate:c,shared:s.shared,callbacks:s.callbacks},t.updateQueue=a;return}t=a.lastBaseUpdate,t===null?a.firstBaseUpdate=e:t.next=e,a.lastBaseUpdate=e}var hu=!1;function cs(){if(hu){var t=ui;if(t!==null)throw t}}function fs(t,e,a,s){hu=!1;var o=t.updateQueue;Xn=!1;var c=o.firstBaseUpdate,y=o.lastBaseUpdate,b=o.shared.pending;if(b!==null){o.shared.pending=null;var C=b,U=C.next;C.next=null,y===null?c=U:y.next=U,y=C;var Y=t.alternate;Y!==null&&(Y=Y.updateQueue,b=Y.lastBaseUpdate,b!==y&&(b===null?Y.firstBaseUpdate=U:b.next=U,Y.lastBaseUpdate=C))}if(c!==null){var X=o.baseState;y=0,Y=U=C=null,b=c;do{var B=b.lane&-536870913,G=B!==b.lane;if(G?(xt&B)===B:(s&B)===B){B!==0&&B===oi&&(hu=!0),Y!==null&&(Y=Y.next={lane:0,tag:b.tag,payload:b.payload,callback:null,next:null});t:{var nt=t,ot=b;B=e;var Ot=a;switch(ot.tag){case 1:if(nt=ot.payload,typeof nt=="function"){X=nt.call(Ot,X,B);break t}X=nt;break t;case 3:nt.flags=nt.flags&-65537|128;case 0:if(nt=ot.payload,B=typeof nt=="function"?nt.call(Ot,X,B):nt,B==null)break t;X=x({},X,B);break t;case 2:Xn=!0}}B=b.callback,B!==null&&(t.flags|=64,G&&(t.flags|=8192),G=o.callbacks,G===null?o.callbacks=[B]:G.push(B))}else G={lane:B,tag:b.tag,payload:b.payload,callback:b.callback,next:null},Y===null?(U=Y=G,C=X):Y=Y.next=G,y|=B;if(b=b.next,b===null){if(b=o.shared.pending,b===null)break;G=b,b=G.next,G.next=null,o.lastBaseUpdate=G,o.shared.pending=null}}while(!0);Y===null&&(C=X),o.baseState=C,o.firstBaseUpdate=U,o.lastBaseUpdate=Y,c===null&&(o.shared.lanes=0),Wn|=y,t.lanes=y,t.memoizedState=X}}function Gh(t,e){if(typeof t!="function")throw Error(r(191,t));t.call(e)}function Yh(t,e){var a=t.callbacks;if(a!==null)for(t.callbacks=null,t=0;tc?c:8;var y=L.T,b={};L.T=b,Mu(t,!1,e,a);try{var C=o(),U=L.S;if(U!==null&&U(b,C),C!==null&&typeof C=="object"&&typeof C.then=="function"){var Y=Bb(C,s);ms(t,e,Y,Me(t))}else ms(t,e,s,Me(t))}catch(X){ms(t,e,{then:function(){},status:"rejected",reason:X},Me())}finally{J.p=c,y!==null&&b.types!==null&&(y.types=b.types),L.T=y}}function Xb(){}function ju(t,e,a,s){if(t.tag!==5)throw Error(r(476));var o=bm(t).queue;xm(t,o,e,tt,a===null?Xb:function(){return Sm(t),a(s)})}function bm(t){var e=t.memoizedState;if(e!==null)return e;e={memoizedState:tt,baseState:tt,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:An,lastRenderedState:tt},next:null};var a={};return e.next={memoizedState:a,baseState:a,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:An,lastRenderedState:a},next:null},t.memoizedState=e,t=t.alternate,t!==null&&(t.memoizedState=e),e}function Sm(t){var e=bm(t);e.next===null&&(e=t.alternate.memoizedState),ms(t,e.next.queue,{},Me())}function Du(){return se(Ds)}function Tm(){return Qt().memoizedState}function Em(){return Qt().memoizedState}function Kb(t){for(var e=t.return;e!==null;){switch(e.tag){case 24:case 3:var a=Me();t=Kn(a);var s=Qn(e,t,a);s!==null&&(Te(s,e,a),us(s,e,a)),e={cache:lu()},t.payload=e;return}e=e.return}}function Qb(t,e,a){var s=Me();a={lane:s,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Xl(t)?Cm(e,a):(a=$o(t,e,a,s),a!==null&&(Te(a,t,s),wm(a,e,s)))}function Am(t,e,a){var s=Me();ms(t,e,a,s)}function ms(t,e,a,s){var o={lane:s,revertLane:0,gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null};if(Xl(t))Cm(e,o);else{var c=t.alternate;if(t.lanes===0&&(c===null||c.lanes===0)&&(c=e.lastRenderedReducer,c!==null))try{var y=e.lastRenderedState,b=c(y,a);if(o.hasEagerState=!0,o.eagerState=b,we(b,y))return Cl(t,e,o,0),zt===null&&Al(),!1}catch{}finally{}if(a=$o(t,e,o,s),a!==null)return Te(a,t,s),wm(a,e,s),!0}return!1}function Mu(t,e,a,s){if(s={lane:2,revertLane:cc(),gesture:null,action:s,hasEagerState:!1,eagerState:null,next:null},Xl(t)){if(e)throw Error(r(479))}else e=$o(t,a,s,2),e!==null&&Te(e,t,2)}function Xl(t){var e=t.alternate;return t===ht||e!==null&&e===ht}function Cm(t,e){hi=Vl=!0;var a=t.pending;a===null?e.next=e:(e.next=a.next,a.next=e),t.pending=e}function wm(t,e,a){if((a&4194048)!==0){var s=e.lanes;s&=t.pendingLanes,a|=s,e.lanes=a,Dd(t,a)}}var ps={readContext:se,use:Gl,useCallback:Yt,useContext:Yt,useEffect:Yt,useImperativeHandle:Yt,useLayoutEffect:Yt,useInsertionEffect:Yt,useMemo:Yt,useReducer:Yt,useRef:Yt,useState:Yt,useDebugValue:Yt,useDeferredValue:Yt,useTransition:Yt,useSyncExternalStore:Yt,useId:Yt,useHostTransitionStatus:Yt,useFormState:Yt,useActionState:Yt,useOptimistic:Yt,useMemoCache:Yt,useCacheRefresh:Yt};ps.useEffectEvent=Yt;var Rm={readContext:se,use:Gl,useCallback:function(t,e){return de().memoizedState=[t,e===void 0?null:e],t},useContext:se,useEffect:cm,useImperativeHandle:function(t,e,a){a=a!=null?a.concat([t]):null,ql(4194308,4,mm.bind(null,e,t),a)},useLayoutEffect:function(t,e){return ql(4194308,4,t,e)},useInsertionEffect:function(t,e){ql(4,2,t,e)},useMemo:function(t,e){var a=de();e=e===void 0?null:e;var s=t();if(Ma){Vn(!0);try{t()}finally{Vn(!1)}}return a.memoizedState=[s,e],s},useReducer:function(t,e,a){var s=de();if(a!==void 0){var o=a(e);if(Ma){Vn(!0);try{a(e)}finally{Vn(!1)}}}else o=e;return s.memoizedState=s.baseState=o,t={pending:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:o},s.queue=t,t=t.dispatch=Qb.bind(null,ht,t),[s.memoizedState,t]},useRef:function(t){var e=de();return t={current:t},e.memoizedState=t},useState:function(t){t=Cu(t);var e=t.queue,a=Am.bind(null,ht,e);return e.dispatch=a,[t.memoizedState,a]},useDebugValue:_u,useDeferredValue:function(t,e){var a=de();return Nu(a,t,e)},useTransition:function(){var t=Cu(!1);return t=xm.bind(null,ht,t.queue,!0,!1),de().memoizedState=t,[!1,t]},useSyncExternalStore:function(t,e,a){var s=ht,o=de();if(St){if(a===void 0)throw Error(r(407));a=a()}else{if(a=e(),zt===null)throw Error(r(349));(xt&127)!==0||Zh(s,e,a)}o.memoizedState=a;var c={value:a,getSnapshot:e};return o.queue=c,cm(Fh.bind(null,s,c,t),[t]),s.flags|=2048,pi(9,{destroy:void 0},$h.bind(null,s,c,a,e),null),a},useId:function(){var t=de(),e=zt.identifierPrefix;if(St){var a=on,s=rn;a=(s&~(1<<32-Ce(s)-1)).toString(32)+a,e="_"+e+"R_"+a,a=Bl++,0<\/script>",c=c.removeChild(c.firstChild);break;case"select":c=typeof s.is=="string"?y.createElement("select",{is:s.is}):y.createElement("select"),s.multiple?c.multiple=!0:s.size&&(c.size=s.size);break;default:c=typeof s.is=="string"?y.createElement(o,{is:s.is}):y.createElement(o)}}c[ae]=e,c[ye]=s;t:for(y=e.child;y!==null;){if(y.tag===5||y.tag===6)c.appendChild(y.stateNode);else if(y.tag!==4&&y.tag!==27&&y.child!==null){y.child.return=y,y=y.child;continue}if(y===e)break t;for(;y.sibling===null;){if(y.return===null||y.return===e)break t;y=y.return}y.sibling.return=y.return,y=y.sibling}e.stateNode=c;t:switch(re(c,o,s),o){case"button":case"input":case"select":case"textarea":s=!!s.autoFocus;break t;case"img":s=!0;break t;default:s=!1}s&&wn(e)}}return Bt(e),Ku(e,e.type,t===null?null:t.memoizedProps,e.pendingProps,a),null;case 6:if(t&&e.stateNode!=null)t.memoizedProps!==s&&wn(e);else{if(typeof s!="string"&&e.stateNode===null)throw Error(r(166));if(t=yt.current,li(e)){if(t=e.stateNode,a=e.memoizedProps,s=null,o=ie,o!==null)switch(o.tag){case 27:case 5:s=o.memoizedProps}t[ae]=e,t=!!(t.nodeValue===a||s!==null&&s.suppressHydrationWarning===!0||Kp(t.nodeValue,a)),t||qn(e,!0)}else t=fr(t).createTextNode(s),t[ae]=e,e.stateNode=t}return Bt(e),null;case 31:if(a=e.memoizedState,t===null||t.memoizedState!==null){if(s=li(e),a!==null){if(t===null){if(!s)throw Error(r(318));if(t=e.memoizedState,t=t!==null?t.dehydrated:null,!t)throw Error(r(557));t[ae]=e}else Ca(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;Bt(e),t=!1}else a=nu(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=a),t=!0;if(!t)return e.flags&256?(Ne(e),e):(Ne(e),null);if((e.flags&128)!==0)throw Error(r(558))}return Bt(e),null;case 13:if(s=e.memoizedState,t===null||t.memoizedState!==null&&t.memoizedState.dehydrated!==null){if(o=li(e),s!==null&&s.dehydrated!==null){if(t===null){if(!o)throw Error(r(318));if(o=e.memoizedState,o=o!==null?o.dehydrated:null,!o)throw Error(r(317));o[ae]=e}else Ca(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;Bt(e),o=!1}else o=nu(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=o),o=!0;if(!o)return e.flags&256?(Ne(e),e):(Ne(e),null)}return Ne(e),(e.flags&128)!==0?(e.lanes=a,e):(a=s!==null,t=t!==null&&t.memoizedState!==null,a&&(s=e.child,o=null,s.alternate!==null&&s.alternate.memoizedState!==null&&s.alternate.memoizedState.cachePool!==null&&(o=s.alternate.memoizedState.cachePool.pool),c=null,s.memoizedState!==null&&s.memoizedState.cachePool!==null&&(c=s.memoizedState.cachePool.pool),c!==o&&(s.flags|=2048)),a!==t&&a&&(e.child.flags|=8192),Fl(e,e.updateQueue),Bt(e),null);case 4:return Xt(),t===null&&mc(e.stateNode.containerInfo),Bt(e),null;case 10:return Tn(e.type),Bt(e),null;case 19:if(K(Kt),s=e.memoizedState,s===null)return Bt(e),null;if(o=(e.flags&128)!==0,c=s.rendering,c===null)if(o)gs(s,!1);else{if(qt!==0||t!==null&&(t.flags&128)!==0)for(t=e.child;t!==null;){if(c=Ul(t),c!==null){for(e.flags|=128,gs(s,!1),t=c.updateQueue,e.updateQueue=t,Fl(e,t),e.subtreeFlags=0,t=a,a=e.child;a!==null;)Ah(a,t),a=a.sibling;return et(Kt,Kt.current&1|2),St&&bn(e,s.treeForkCount),e.child}t=t.sibling}s.tail!==null&&Ee()>er&&(e.flags|=128,o=!0,gs(s,!1),e.lanes=4194304)}else{if(!o)if(t=Ul(c),t!==null){if(e.flags|=128,o=!0,t=t.updateQueue,e.updateQueue=t,Fl(e,t),gs(s,!0),s.tail===null&&s.tailMode==="hidden"&&!c.alternate&&!St)return Bt(e),null}else 2*Ee()-s.renderingStartTime>er&&a!==536870912&&(e.flags|=128,o=!0,gs(s,!1),e.lanes=4194304);s.isBackwards?(c.sibling=e.child,e.child=c):(t=s.last,t!==null?t.sibling=c:e.child=c,s.last=c)}return s.tail!==null?(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=Ee(),t.sibling=null,a=Kt.current,et(Kt,o?a&1|2:a&1),St&&bn(e,s.treeForkCount),t):(Bt(e),null);case 22:case 23:return Ne(e),pu(),s=e.memoizedState!==null,t!==null?t.memoizedState!==null!==s&&(e.flags|=8192):s&&(e.flags|=8192),s?(a&536870912)!==0&&(e.flags&128)===0&&(Bt(e),e.subtreeFlags&6&&(e.flags|=8192)):Bt(e),a=e.updateQueue,a!==null&&Fl(e,a.retryQueue),a=null,t!==null&&t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),s=null,e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(s=e.memoizedState.cachePool.pool),s!==a&&(e.flags|=2048),t!==null&&K(_a),null;case 24:return a=null,t!==null&&(a=t.memoizedState.cache),e.memoizedState.cache!==a&&(e.flags|=2048),Tn(Zt),Bt(e),null;case 25:return null;case 30:return null}throw Error(r(156,e.tag))}function Wb(t,e){switch(tu(e),e.tag){case 1:return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 3:return Tn(Zt),Xt(),t=e.flags,(t&65536)!==0&&(t&128)===0?(e.flags=t&-65537|128,e):null;case 26:case 27:case 5:return rl(e),null;case 31:if(e.memoizedState!==null){if(Ne(e),e.alternate===null)throw Error(r(340));Ca()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 13:if(Ne(e),t=e.memoizedState,t!==null&&t.dehydrated!==null){if(e.alternate===null)throw Error(r(340));Ca()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 19:return K(Kt),null;case 4:return Xt(),null;case 10:return Tn(e.type),null;case 22:case 23:return Ne(e),pu(),t!==null&&K(_a),t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 24:return Tn(Zt),null;case 25:return null;default:return null}}function Jm(t,e){switch(tu(e),e.tag){case 3:Tn(Zt),Xt();break;case 26:case 27:case 5:rl(e);break;case 4:Xt();break;case 31:e.memoizedState!==null&&Ne(e);break;case 13:Ne(e);break;case 19:K(Kt);break;case 10:Tn(e.type);break;case 22:case 23:Ne(e),pu(),t!==null&&K(_a);break;case 24:Tn(Zt)}}function vs(t,e){try{var a=e.updateQueue,s=a!==null?a.lastEffect:null;if(s!==null){var o=s.next;a=o;do{if((a.tag&t)===t){s=void 0;var c=a.create,y=a.inst;s=c(),y.destroy=s}a=a.next}while(a!==o)}}catch(b){jt(e,e.return,b)}}function Fn(t,e,a){try{var s=e.updateQueue,o=s!==null?s.lastEffect:null;if(o!==null){var c=o.next;s=c;do{if((s.tag&t)===t){var y=s.inst,b=y.destroy;if(b!==void 0){y.destroy=void 0,o=e;var C=a,U=b;try{U()}catch(Y){jt(o,C,Y)}}}s=s.next}while(s!==c)}}catch(Y){jt(e,e.return,Y)}}function Wm(t){var e=t.updateQueue;if(e!==null){var a=t.stateNode;try{Yh(e,a)}catch(s){jt(t,t.return,s)}}}function Im(t,e,a){a.props=Oa(t.type,t.memoizedProps),a.state=t.memoizedState;try{a.componentWillUnmount()}catch(s){jt(t,e,s)}}function xs(t,e){try{var a=t.ref;if(a!==null){switch(t.tag){case 26:case 27:case 5:var s=t.stateNode;break;case 30:s=t.stateNode;break;default:s=t.stateNode}typeof a=="function"?t.refCleanup=a(s):a.current=s}}catch(o){jt(t,e,o)}}function un(t,e){var a=t.ref,s=t.refCleanup;if(a!==null)if(typeof s=="function")try{s()}catch(o){jt(t,e,o)}finally{t.refCleanup=null,t=t.alternate,t!=null&&(t.refCleanup=null)}else if(typeof a=="function")try{a(null)}catch(o){jt(t,e,o)}else a.current=null}function tp(t){var e=t.type,a=t.memoizedProps,s=t.stateNode;try{t:switch(e){case"button":case"input":case"select":case"textarea":a.autoFocus&&s.focus();break t;case"img":a.src?s.src=a.src:a.srcSet&&(s.srcset=a.srcSet)}}catch(o){jt(t,t.return,o)}}function Qu(t,e,a){try{var s=t.stateNode;b1(s,t.type,a,e),s[ye]=e}catch(o){jt(t,t.return,o)}}function ep(t){return t.tag===5||t.tag===3||t.tag===26||t.tag===27&&aa(t.type)||t.tag===4}function Zu(t){t:for(;;){for(;t.sibling===null;){if(t.return===null||ep(t.return))return null;t=t.return}for(t.sibling.return=t.return,t=t.sibling;t.tag!==5&&t.tag!==6&&t.tag!==18;){if(t.tag===27&&aa(t.type)||t.flags&2||t.child===null||t.tag===4)continue t;t.child.return=t,t=t.child}if(!(t.flags&2))return t.stateNode}}function $u(t,e,a){var s=t.tag;if(s===5||s===6)t=t.stateNode,e?(a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a).insertBefore(t,e):(e=a.nodeType===9?a.body:a.nodeName==="HTML"?a.ownerDocument.body:a,e.appendChild(t),a=a._reactRootContainer,a!=null||e.onclick!==null||(e.onclick=gn));else if(s!==4&&(s===27&&aa(t.type)&&(a=t.stateNode,e=null),t=t.child,t!==null))for($u(t,e,a),t=t.sibling;t!==null;)$u(t,e,a),t=t.sibling}function Jl(t,e,a){var s=t.tag;if(s===5||s===6)t=t.stateNode,e?a.insertBefore(t,e):a.appendChild(t);else if(s!==4&&(s===27&&aa(t.type)&&(a=t.stateNode),t=t.child,t!==null))for(Jl(t,e,a),t=t.sibling;t!==null;)Jl(t,e,a),t=t.sibling}function np(t){var e=t.stateNode,a=t.memoizedProps;try{for(var s=t.type,o=e.attributes;o.length;)e.removeAttributeNode(o[0]);re(e,s,a),e[ae]=t,e[ye]=a}catch(c){jt(t,t.return,c)}}var Rn=!1,Jt=!1,Fu=!1,ap=typeof WeakSet=="function"?WeakSet:Set,ne=null;function Ib(t,e){if(t=t.containerInfo,gc=vr,t=ph(t),qo(t)){if("selectionStart"in t)var a={start:t.selectionStart,end:t.selectionEnd};else t:{a=(a=t.ownerDocument)&&a.defaultView||window;var s=a.getSelection&&a.getSelection();if(s&&s.rangeCount!==0){a=s.anchorNode;var o=s.anchorOffset,c=s.focusNode;s=s.focusOffset;try{a.nodeType,c.nodeType}catch{a=null;break t}var y=0,b=-1,C=-1,U=0,Y=0,X=t,B=null;e:for(;;){for(var G;X!==a||o!==0&&X.nodeType!==3||(b=y+o),X!==c||s!==0&&X.nodeType!==3||(C=y+s),X.nodeType===3&&(y+=X.nodeValue.length),(G=X.firstChild)!==null;)B=X,X=G;for(;;){if(X===t)break e;if(B===a&&++U===o&&(b=y),B===c&&++Y===s&&(C=y),(G=X.nextSibling)!==null)break;X=B,B=X.parentNode}X=G}a=b===-1||C===-1?null:{start:b,end:C}}else a=null}a=a||{start:0,end:0}}else a=null;for(vc={focusedElem:t,selectionRange:a},vr=!1,ne=e;ne!==null;)if(e=ne,t=e.child,(e.subtreeFlags&1028)!==0&&t!==null)t.return=e,ne=t;else for(;ne!==null;){switch(e=ne,c=e.alternate,t=e.flags,e.tag){case 0:if((t&4)!==0&&(t=e.updateQueue,t=t!==null?t.events:null,t!==null))for(a=0;a title"))),re(c,s,a),c[ae]=t,ee(c),s=c;break t;case"link":var y=uy("link","href",o).get(s+(a.href||""));if(y){for(var b=0;bOt&&(y=Ot,Ot=ot,ot=y);var z=hh(b,ot),j=hh(b,Ot);if(z&&j&&(G.rangeCount!==1||G.anchorNode!==z.node||G.anchorOffset!==z.offset||G.focusNode!==j.node||G.focusOffset!==j.offset)){var k=X.createRange();k.setStart(z.node,z.offset),G.removeAllRanges(),ot>Ot?(G.addRange(k),G.extend(j.node,j.offset)):(k.setEnd(j.node,j.offset),G.addRange(k))}}}}for(X=[],G=b;G=G.parentNode;)G.nodeType===1&&X.push({element:G,left:G.scrollLeft,top:G.scrollTop});for(typeof b.focus=="function"&&b.focus(),b=0;ba?32:a,L.T=null,a=ac,ac=null;var c=ta,y=Mn;if(It=0,bi=ta=null,Mn=0,(Ct&6)!==0)throw Error(r(331));var b=Ct;if(Ct|=4,mp(c.current),fp(c,c.current,y,a),Ct=b,Cs(0,!1),Ae&&typeof Ae.onPostCommitFiberRoot=="function")try{Ae.onPostCommitFiberRoot(qi,c)}catch{}return!0}finally{J.p=o,L.T=s,Mp(t,e)}}function zp(t,e,a){e=Ve(a,e),e=ku(t.stateNode,e,2),t=Qn(t,e,2),t!==null&&(Xi(t,2),cn(t))}function jt(t,e,a){if(t.tag===3)zp(t,t,a);else for(;e!==null;){if(e.tag===3){zp(e,t,a);break}else if(e.tag===1){var s=e.stateNode;if(typeof e.type.getDerivedStateFromError=="function"||typeof s.componentDidCatch=="function"&&(In===null||!In.has(s))){t=Ve(a,t),a=Lm(2),s=Qn(e,a,2),s!==null&&(km(a,s,e,t),Xi(s,2),cn(s));break}}e=e.return}}function rc(t,e,a){var s=t.pingCache;if(s===null){s=t.pingCache=new n1;var o=new Set;s.set(e,o)}else o=s.get(e),o===void 0&&(o=new Set,s.set(e,o));o.has(a)||(Iu=!0,o.add(a),t=r1.bind(null,t,e,a),e.then(t,t))}function r1(t,e,a){var s=t.pingCache;s!==null&&s.delete(e),t.pingedLanes|=t.suspendedLanes&a,t.warmLanes&=~a,zt===t&&(xt&a)===a&&(qt===4||qt===3&&(xt&62914560)===xt&&300>Ee()-tr?(Ct&2)===0&&Si(t,0):tc|=a,xi===xt&&(xi=0)),cn(t)}function Lp(t,e){e===0&&(e=Nd()),t=Ea(t,e),t!==null&&(Xi(t,e),cn(t))}function o1(t){var e=t.memoizedState,a=0;e!==null&&(a=e.retryLane),Lp(t,a)}function u1(t,e){var a=0;switch(t.tag){case 31:case 13:var s=t.stateNode,o=t.memoizedState;o!==null&&(a=o.retryLane);break;case 19:s=t.stateNode;break;case 22:s=t.stateNode._retryCache;break;default:throw Error(r(314))}s!==null&&s.delete(e),Lp(t,a)}function c1(t,e){return bo(t,e)}var rr=null,Ei=null,oc=!1,or=!1,uc=!1,na=0;function cn(t){t!==Ei&&t.next===null&&(Ei===null?rr=Ei=t:Ei=Ei.next=t),or=!0,oc||(oc=!0,d1())}function Cs(t,e){if(!uc&&or){uc=!0;do for(var a=!1,s=rr;s!==null;){if(t!==0){var o=s.pendingLanes;if(o===0)var c=0;else{var y=s.suspendedLanes,b=s.pingedLanes;c=(1<<31-Ce(42|t)+1)-1,c&=o&~(y&~b),c=c&201326741?c&201326741|1:c?c|2:0}c!==0&&(a=!0,Bp(s,c))}else c=xt,c=dl(s,s===zt?c:0,s.cancelPendingCommit!==null||s.timeoutHandle!==-1),(c&3)===0||Pi(s,c)||(a=!0,Bp(s,c));s=s.next}while(a);uc=!1}}function f1(){kp()}function kp(){or=oc=!1;var t=0;na!==0&&T1()&&(t=na);for(var e=Ee(),a=null,s=rr;s!==null;){var o=s.next,c=Up(s,e);c===0?(s.next=null,a===null?rr=o:a.next=o,o===null&&(Ei=a)):(a=s,(t!==0||(c&3)!==0)&&(or=!0)),s=o}It!==0&&It!==5||Cs(t),na!==0&&(na=0)}function Up(t,e){for(var a=t.suspendedLanes,s=t.pingedLanes,o=t.expirationTimes,c=t.pendingLanes&-62914561;0b)break;var Y=C.transferSize,X=C.initiatorType;Y&&Qp(X)&&(C=C.responseEnd,y+=Y*(C"u"?null:document;function sy(t,e,a){var s=Ai;if(s&&typeof e=="string"&&e){var o=ke(e);o='link[rel="'+t+'"][href="'+o+'"]',typeof a=="string"&&(o+='[crossorigin="'+a+'"]'),iy.has(o)||(iy.add(o),t={rel:t,crossOrigin:a,href:e},s.querySelector(o)===null&&(e=s.createElement("link"),re(e,"link",t),ee(e),s.head.appendChild(e)))}}function D1(t){On.D(t),sy("dns-prefetch",t,null)}function M1(t,e){On.C(t,e),sy("preconnect",t,e)}function O1(t,e,a){On.L(t,e,a);var s=Ai;if(s&&t&&e){var o='link[rel="preload"][as="'+ke(e)+'"]';e==="image"&&a&&a.imageSrcSet?(o+='[imagesrcset="'+ke(a.imageSrcSet)+'"]',typeof a.imageSizes=="string"&&(o+='[imagesizes="'+ke(a.imageSizes)+'"]')):o+='[href="'+ke(t)+'"]';var c=o;switch(e){case"style":c=Ci(t);break;case"script":c=wi(t)}Pe.has(c)||(t=x({rel:"preload",href:e==="image"&&a&&a.imageSrcSet?void 0:t,as:e},a),Pe.set(c,t),s.querySelector(o)!==null||e==="style"&&s.querySelector(Ns(c))||e==="script"&&s.querySelector(js(c))||(e=s.createElement("link"),re(e,"link",t),ee(e),s.head.appendChild(e)))}}function z1(t,e){On.m(t,e);var a=Ai;if(a&&t){var s=e&&typeof e.as=="string"?e.as:"script",o='link[rel="modulepreload"][as="'+ke(s)+'"][href="'+ke(t)+'"]',c=o;switch(s){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":c=wi(t)}if(!Pe.has(c)&&(t=x({rel:"modulepreload",href:t},e),Pe.set(c,t),a.querySelector(o)===null)){switch(s){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(a.querySelector(js(c)))return}s=a.createElement("link"),re(s,"link",t),ee(s),a.head.appendChild(s)}}}function L1(t,e,a){On.S(t,e,a);var s=Ai;if(s&&t){var o=Qa(s).hoistableStyles,c=Ci(t);e=e||"default";var y=o.get(c);if(!y){var b={loading:0,preload:null};if(y=s.querySelector(Ns(c)))b.loading=5;else{t=x({rel:"stylesheet",href:t,"data-precedence":e},a),(a=Pe.get(c))&&Cc(t,a);var C=y=s.createElement("link");ee(C),re(C,"link",t),C._p=new Promise(function(U,Y){C.onload=U,C.onerror=Y}),C.addEventListener("load",function(){b.loading|=1}),C.addEventListener("error",function(){b.loading|=2}),b.loading|=4,hr(y,e,s)}y={type:"stylesheet",instance:y,count:1,state:b},o.set(c,y)}}}function k1(t,e){On.X(t,e);var a=Ai;if(a&&t){var s=Qa(a).hoistableScripts,o=wi(t),c=s.get(o);c||(c=a.querySelector(js(o)),c||(t=x({src:t,async:!0},e),(e=Pe.get(o))&&wc(t,e),c=a.createElement("script"),ee(c),re(c,"link",t),a.head.appendChild(c)),c={type:"script",instance:c,count:1,state:null},s.set(o,c))}}function U1(t,e){On.M(t,e);var a=Ai;if(a&&t){var s=Qa(a).hoistableScripts,o=wi(t),c=s.get(o);c||(c=a.querySelector(js(o)),c||(t=x({src:t,async:!0,type:"module"},e),(e=Pe.get(o))&&wc(t,e),c=a.createElement("script"),ee(c),re(c,"link",t),a.head.appendChild(c)),c={type:"script",instance:c,count:1,state:null},s.set(o,c))}}function ly(t,e,a,s){var o=(o=yt.current)?dr(o):null;if(!o)throw Error(r(446));switch(t){case"meta":case"title":return null;case"style":return typeof a.precedence=="string"&&typeof a.href=="string"?(e=Ci(a.href),a=Qa(o).hoistableStyles,s=a.get(e),s||(s={type:"style",instance:null,count:0,state:null},a.set(e,s)),s):{type:"void",instance:null,count:0,state:null};case"link":if(a.rel==="stylesheet"&&typeof a.href=="string"&&typeof a.precedence=="string"){t=Ci(a.href);var c=Qa(o).hoistableStyles,y=c.get(t);if(y||(o=o.ownerDocument||o,y={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},c.set(t,y),(c=o.querySelector(Ns(t)))&&!c._p&&(y.instance=c,y.state.loading=5),Pe.has(t)||(a={rel:"preload",as:"style",href:a.href,crossOrigin:a.crossOrigin,integrity:a.integrity,media:a.media,hrefLang:a.hrefLang,referrerPolicy:a.referrerPolicy},Pe.set(t,a),c||V1(o,t,a,y.state))),e&&s===null)throw Error(r(528,""));return y}if(e&&s!==null)throw Error(r(529,""));return null;case"script":return e=a.async,a=a.src,typeof a=="string"&&e&&typeof e!="function"&&typeof e!="symbol"?(e=wi(a),a=Qa(o).hoistableScripts,s=a.get(e),s||(s={type:"script",instance:null,count:0,state:null},a.set(e,s)),s):{type:"void",instance:null,count:0,state:null};default:throw Error(r(444,t))}}function Ci(t){return'href="'+ke(t)+'"'}function Ns(t){return'link[rel="stylesheet"]['+t+"]"}function ry(t){return x({},t,{"data-precedence":t.precedence,precedence:null})}function V1(t,e,a,s){t.querySelector('link[rel="preload"][as="style"]['+e+"]")?s.loading=1:(e=t.createElement("link"),s.preload=e,e.addEventListener("load",function(){return s.loading|=1}),e.addEventListener("error",function(){return s.loading|=2}),re(e,"link",a),ee(e),t.head.appendChild(e))}function wi(t){return'[src="'+ke(t)+'"]'}function js(t){return"script[async]"+t}function oy(t,e,a){if(e.count++,e.instance===null)switch(e.type){case"style":var s=t.querySelector('style[data-href~="'+ke(a.href)+'"]');if(s)return e.instance=s,ee(s),s;var o=x({},a,{"data-href":a.href,"data-precedence":a.precedence,href:null,precedence:null});return s=(t.ownerDocument||t).createElement("style"),ee(s),re(s,"style",o),hr(s,a.precedence,t),e.instance=s;case"stylesheet":o=Ci(a.href);var c=t.querySelector(Ns(o));if(c)return e.state.loading|=4,e.instance=c,ee(c),c;s=ry(a),(o=Pe.get(o))&&Cc(s,o),c=(t.ownerDocument||t).createElement("link"),ee(c);var y=c;return y._p=new Promise(function(b,C){y.onload=b,y.onerror=C}),re(c,"link",s),e.state.loading|=4,hr(c,a.precedence,t),e.instance=c;case"script":return c=wi(a.src),(o=t.querySelector(js(c)))?(e.instance=o,ee(o),o):(s=a,(o=Pe.get(c))&&(s=x({},a),wc(s,o)),t=t.ownerDocument||t,o=t.createElement("script"),ee(o),re(o,"link",s),t.head.appendChild(o),e.instance=o);case"void":return null;default:throw Error(r(443,e.type))}else e.type==="stylesheet"&&(e.state.loading&4)===0&&(s=e.instance,e.state.loading|=4,hr(s,a.precedence,t));return e.instance}function hr(t,e,a){for(var s=a.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),o=s.length?s[s.length-1]:null,c=o,y=0;y title"):null)}function B1(t,e,a){if(a===1||e.itemProp!=null)return!1;switch(t){case"meta":case"title":return!0;case"style":if(typeof e.precedence!="string"||typeof e.href!="string"||e.href==="")break;return!0;case"link":if(typeof e.rel!="string"||typeof e.href!="string"||e.href===""||e.onLoad||e.onError)break;switch(e.rel){case"stylesheet":return t=e.disabled,typeof e.precedence=="string"&&t==null;default:return!0}case"script":if(e.async&&typeof e.async!="function"&&typeof e.async!="symbol"&&!e.onLoad&&!e.onError&&e.src&&typeof e.src=="string")return!0}return!1}function fy(t){return!(t.type==="stylesheet"&&(t.state.loading&3)===0)}function H1(t,e,a,s){if(a.type==="stylesheet"&&(typeof s.media!="string"||matchMedia(s.media).matches!==!1)&&(a.state.loading&4)===0){if(a.instance===null){var o=Ci(s.href),c=e.querySelector(Ns(o));if(c){e=c._p,e!==null&&typeof e=="object"&&typeof e.then=="function"&&(t.count++,t=pr.bind(t),e.then(t,t)),a.state.loading|=4,a.instance=c,ee(c);return}c=e.ownerDocument||e,s=ry(s),(o=Pe.get(o))&&Cc(s,o),c=c.createElement("link"),ee(c);var y=c;y._p=new Promise(function(b,C){y.onload=b,y.onerror=C}),re(c,"link",s),a.instance=c}t.stylesheets===null&&(t.stylesheets=new Map),t.stylesheets.set(a,e),(e=a.state.preload)&&(a.state.loading&3)===0&&(t.count++,a=pr.bind(t),e.addEventListener("load",a),e.addEventListener("error",a))}}var Rc=0;function G1(t,e){return t.stylesheets&&t.count===0&&gr(t,t.stylesheets),0Rc?50:800)+e);return t.unsuspend=a,function(){t.unsuspend=null,clearTimeout(s),clearTimeout(o)}}:null}function pr(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)gr(this,this.stylesheets);else if(this.unsuspend){var t=this.unsuspend;this.unsuspend=null,t()}}}var yr=null;function gr(t,e){t.stylesheets=null,t.unsuspend!==null&&(t.count++,yr=new Map,e.forEach(Y1,t),yr=null,pr.call(t))}function Y1(t,e){if(!(e.state.loading&4)){var a=yr.get(t);if(a)var s=a.get(null);else{a=new Map,yr.set(t,a);for(var o=t.querySelectorAll("link[data-precedence],style[data-precedence]"),c=0;c"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(i){console.error(i)}}return n(),kc.exports=iS(),kc.exports}var lS=sS();const rS=mg(lS);/** - * react-router v7.18.1 - * - * Copyright (c) Remix Software Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE.md file in the root directory of this source tree. - * - * @license MIT - */var Bf=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,pg=/^[\\/]{2}/;function oS(n,i){return i+n.replace(/\\/g,"/")}var Ly="popstate";function ky(n){return typeof n=="object"&&n!=null&&"pathname"in n&&"search"in n&&"hash"in n&&"state"in n&&"key"in n}function uS(n={}){function i(r,u){var p;let d=(p=u.state)==null?void 0:p.masked,{pathname:f,search:h,hash:m}=d||r.location;return rf("",{pathname:f,search:h,hash:m},u.state&&u.state.usr||null,u.state&&u.state.key||"default",d?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function l(r,u){return typeof u=="string"?u:Xs(u)}return fS(i,l,null,n)}function Gt(n,i){if(n===!1||n===null||typeof n>"u")throw new Error(i)}function an(n,i){if(!n){typeof console<"u"&&console.warn(i);try{throw new Error(i)}catch{}}}function cS(){return Math.random().toString(36).substring(2,10)}function Uy(n,i){return{usr:n.state,key:n.key,idx:i,masked:n.mask?{pathname:n.pathname,search:n.search,hash:n.hash}:void 0}}function rf(n,i,l=null,r,u){return{pathname:typeof n=="string"?n:n.pathname,search:"",hash:"",...typeof i=="string"?Li(i):i,state:l,key:i&&i.key||r||cS(),mask:u}}function Xs({pathname:n="/",search:i="",hash:l=""}){return i&&i!=="?"&&(n+=i.charAt(0)==="?"?i:"?"+i),l&&l!=="#"&&(n+=l.charAt(0)==="#"?l:"#"+l),n}function Li(n){let i={};if(n){let l=n.indexOf("#");l>=0&&(i.hash=n.substring(l),n=n.substring(0,l));let r=n.indexOf("?");r>=0&&(i.search=n.substring(r),n=n.substring(0,r)),n&&(i.pathname=n)}return i}function fS(n,i,l,r={}){let{window:u=document.defaultView,v5Compat:d=!1}=r,f=u.history,h="POP",m=null,p=v();p==null&&(p=0,f.replaceState({...f.state,idx:p},""));function v(){return(f.state||{idx:null}).idx}function x(){h="POP";let _=v(),R=_==null?null:_-p;p=_,m&&m({action:h,location:w.location,delta:R})}function S(_,R){h="PUSH";let O=ky(_)?_:rf(w.location,_,R);p=v()+1;let D=Uy(O,p),M=w.createHref(O.mask||O);try{f.pushState(D,"",M)}catch(H){if(H instanceof DOMException&&H.name==="DataCloneError")throw H;u.location.assign(M)}d&&m&&m({action:h,location:w.location,delta:1})}function E(_,R){h="REPLACE";let O=ky(_)?_:rf(w.location,_,R);p=v();let D=Uy(O,p),M=w.createHref(O.mask||O);f.replaceState(D,"",M),d&&m&&m({action:h,location:w.location,delta:0})}function A(_){return dS(u,_)}let w={get action(){return h},get location(){return n(u,f)},listen(_){if(m)throw new Error("A history only accepts one active listener");return u.addEventListener(Ly,x),m=_,()=>{u.removeEventListener(Ly,x),m=null}},createHref(_){return i(u,_)},createURL:A,encodeLocation(_){let R=A(_);return{pathname:R.pathname,search:R.search,hash:R.hash}},push:S,replace:E,go(_){return f.go(_)}};return w}function dS(n,i,l=!1){let r="http://localhost";n&&(r=n.location.origin!=="null"?n.location.origin:n.location.href),Gt(r,"No window.location.(origin|href) available to create URL");let u=typeof i=="string"?i:Xs(i);return u=u.replace(/ $/,"%20"),!l&&pg.test(u)&&(u=r+u),new URL(u,r)}function yg(n,i,l="/"){return hS(n,i,l,!1)}function hS(n,i,l,r,u){let d=typeof i=="string"?Li(i):i,f=kn(d.pathname||"/",l);if(f==null)return null;let h=mS(n),m=null,p=CS(f);for(let v=0;m==null&&v{let v={relativePath:p===void 0?f.path||"":p,caseSensitive:f.caseSensitive===!0,childrenIndex:h,route:f};if(v.relativePath.startsWith("/")){if(!v.relativePath.startsWith(r)&&m)return;Gt(v.relativePath.startsWith(r),`Absolute route path "${v.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),v.relativePath=v.relativePath.slice(r.length)}let x=tn([r,v.relativePath]),S=l.concat(v);f.children&&f.children.length>0&&(Gt(f.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${x}".`),gg(f.children,i,S,x,m)),!(f.path==null&&!f.index)&&i.push({path:x,score:TS(x,f.index),routesMeta:S.map((E,A)=>{let[w,_]=bg(E.relativePath,E.caseSensitive,A===S.length-1);return{...E,matcher:w,compiledParams:_}})})};return n.forEach((f,h)=>{var m;if(f.path===""||!((m=f.path)!=null&&m.includes("?")))d(f,h);else for(let p of vg(f.path))d(f,h,!0,p)}),i}function vg(n){let i=n.split("/");if(i.length===0)return[];let[l,...r]=i,u=l.endsWith("?"),d=l.replace(/\?$/,"");if(r.length===0)return u?[d,""]:[d];let f=vg(r.join("/")),h=[];return h.push(...f.map(m=>m===""?d:[d,m].join("/"))),u&&h.push(...f),h.map(m=>n.startsWith("/")&&m===""?"/":m)}function pS(n){n.sort((i,l)=>i.score!==l.score?l.score-i.score:ES(i.routesMeta.map(r=>r.childrenIndex),l.routesMeta.map(r=>r.childrenIndex)))}var yS=/^:[\w-]+$/,gS=3,vS=2,xS=1,bS=10,SS=-2,Vy=n=>n==="*";function TS(n,i){let l=n.split("/"),r=l.length;return l.some(Vy)&&(r+=SS),i&&(r+=vS),l.filter(u=>!Vy(u)).reduce((u,d)=>u+(yS.test(d)?gS:d===""?xS:bS),r)}function ES(n,i){return n.length===i.length&&n.slice(0,-1).every((r,u)=>r===i[u])?n[n.length-1]-i[i.length-1]:0}function AS(n,i,l=!1){let{routesMeta:r}=n,u={},d="/",f=[];for(let h=0;h{if(v==="*"){let A=h[S]||"";f=d.slice(0,d.length-A.length).replace(/(.)\/+$/,"$1")}const E=h[S];return x&&!E?p[v]=void 0:p[v]=(E||"").replace(/%2F/g,"/"),p},{}),pathname:d,pathnameBase:f,pattern:n}}function bg(n,i=!1,l=!0){an(n==="*"||!n.endsWith("*")||n.endsWith("/*"),`Route path "${n}" will be treated as if it were "${n.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${n.replace(/\*$/,"/*")}".`);let r=[],u="^"+n.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(f,h,m,p,v)=>{if(r.push({paramName:h,isOptional:m!=null}),m){let x=v.charAt(p+f.length);return x&&x!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return n.endsWith("*")?(r.push({paramName:"*"}),u+=n==="*"||n==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):l?u+="\\/*$":n!==""&&n!=="/"&&(u+="(?:(?=\\/|$))"),[new RegExp(u,i?void 0:"i"),r]}function CS(n){try{return n.split("/").map(i=>decodeURIComponent(i).replace(/\//g,"%2F")).join("/")}catch(i){return an(!1,`The URL path "${n}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${i}).`),n}}function kn(n,i){if(i==="/")return n;if(!n.toLowerCase().startsWith(i.toLowerCase()))return null;let l=i.endsWith("/")?i.length-1:i.length,r=n.charAt(l);return r&&r!=="/"?null:n.slice(l)||"/"}function wS(n,i="/"){let{pathname:l,search:r="",hash:u=""}=typeof n=="string"?Li(n):n,d;return l?(l=Sg(l),l.startsWith("/")?d=By(l.substring(1),"/"):d=By(l,i)):d=i,{pathname:d,search:NS(r),hash:jS(u)}}function By(n,i){let l=Xr(i).split("/");return n.split("/").forEach(u=>{u===".."?l.length>1&&l.pop():u!=="."&&l.push(u)}),l.length>1?l.join("/"):"/"}function Hc(n,i,l,r){return`Cannot include a '${n}' character in a manually specified \`to.${i}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${l}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function RS(n){return n.filter((i,l)=>l===0||i.route.path&&i.route.path.length>0)}function Hf(n){let i=RS(n);return i.map((l,r)=>r===i.length-1?l.pathname:l.pathnameBase)}function no(n,i,l,r=!1){let u;typeof n=="string"?u=Li(n):(u={...n},Gt(!u.pathname||!u.pathname.includes("?"),Hc("?","pathname","search",u)),Gt(!u.pathname||!u.pathname.includes("#"),Hc("#","pathname","hash",u)),Gt(!u.search||!u.search.includes("#"),Hc("#","search","hash",u)));let d=n===""||u.pathname==="",f=d?"/":u.pathname,h;if(f==null)h=l;else{let x=i.length-1;if(!r&&f.startsWith("..")){let S=f.split("/");for(;S[0]==="..";)S.shift(),x-=1;u.pathname=S.join("/")}h=x>=0?i[x]:"/"}let m=wS(u,h),p=f&&f!=="/"&&f.endsWith("/"),v=(d||f===".")&&l.endsWith("/");return!m.pathname.endsWith("/")&&(p||v)&&(m.pathname+="/"),m}var Sg=n=>n.replace(/[\\/]{2,}/g,"/"),tn=n=>Sg(n.join("/")),Xr=n=>n.replace(/\/+$/,""),_S=n=>Xr(n).replace(/^\/*/,"/"),NS=n=>!n||n==="?"?"":n.startsWith("?")?n:"?"+n,jS=n=>!n||n==="#"?"":n.startsWith("#")?n:"#"+n,DS=class{constructor(n,i,l,r=!1){this.status=n,this.statusText=i||"",this.internal=r,l instanceof Error?(this.data=l.toString(),this.error=l):this.data=l}};function MS(n){return n!=null&&typeof n.status=="number"&&typeof n.statusText=="string"&&typeof n.internal=="boolean"&&"data"in n}function OS(n){let i=n.map(l=>l.route.path).filter(Boolean);return tn(i)||"/"}var Tg=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Eg(n,i){let l=n;if(typeof l!="string"||!Bf.test(l))return{absoluteURL:void 0,isExternal:!1,to:l};let r=l,u=!1;if(Tg)try{let d=new URL(window.location.href),f=pg.test(l)?new URL(oS(l,d.protocol)):new URL(l),h=kn(f.pathname,i);f.origin===d.origin&&h!=null?l=h+f.search+f.hash:u=!0}catch{an(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:u,to:l}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var Ag=["POST","PUT","PATCH","DELETE"];new Set(Ag);var zS=["GET",...Ag];new Set(zS);var LS=["about:","blob:","chrome:","chrome-untrusted:","content:","data:","devtools:","file:","filesystem:","javascript:"];function kS(n){try{return LS.includes(new URL(n).protocol)}catch{return!1}}var ki=T.createContext(null);ki.displayName="DataRouter";var ao=T.createContext(null);ao.displayName="DataRouterState";var Cg=T.createContext(!1);function US(){return T.useContext(Cg)}var wg=T.createContext({isTransitioning:!1});wg.displayName="ViewTransition";var VS=T.createContext(new Map);VS.displayName="Fetchers";var BS=T.createContext(null);BS.displayName="Await";var ze=T.createContext(null);ze.displayName="Navigation";var Is=T.createContext(null);Is.displayName="Location";var sn=T.createContext({outlet:null,matches:[],isDataRoute:!1});sn.displayName="Route";var Gf=T.createContext(null);Gf.displayName="RouteError";var Rg="REACT_ROUTER_ERROR",HS="REDIRECT",GS="ROUTE_ERROR_RESPONSE";function YS(n){if(n.startsWith(`${Rg}:${HS}:{`))try{let i=JSON.parse(n.slice(28));if(typeof i=="object"&&i&&typeof i.status=="number"&&typeof i.statusText=="string"&&typeof i.location=="string"&&typeof i.reloadDocument=="boolean"&&typeof i.replace=="boolean")return i}catch{}}function qS(n){if(n.startsWith(`${Rg}:${GS}:{`))try{let i=JSON.parse(n.slice(40));if(typeof i=="object"&&i&&typeof i.status=="number"&&typeof i.statusText=="string")return new DS(i.status,i.statusText,i.data)}catch{}}function PS(n,{relative:i}={}){Gt(Ui(),"useHref() may be used only in the context of a component.");let{basename:l,navigator:r}=T.useContext(ze),{hash:u,pathname:d,search:f}=tl(n,{relative:i}),h=d;return l!=="/"&&(h=d==="/"?l:tn([l,d])),r.createHref({pathname:h,search:f,hash:u})}function Ui(){return T.useContext(Is)!=null}function ln(){return Gt(Ui(),"useLocation() may be used only in the context of a component."),T.useContext(Is).location}var _g="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Ng(n){T.useContext(ze).static||T.useLayoutEffect(n)}function pa(){let{isDataRoute:n}=T.useContext(sn);return n?iT():XS()}function XS(){Gt(Ui(),"useNavigate() may be used only in the context of a component.");let n=T.useContext(ki),{basename:i,navigator:l}=T.useContext(ze),{matches:r}=T.useContext(sn),{pathname:u}=ln(),d=JSON.stringify(Hf(r)),f=T.useRef(!1);return Ng(()=>{f.current=!0}),T.useCallback((m,p={})=>{if(an(f.current,_g),!f.current)return;if(typeof m=="number"){l.go(m);return}let v=no(m,JSON.parse(d),u,p.relative==="path");n==null&&i!=="/"&&(v.pathname=v.pathname==="/"?i:tn([i,v.pathname])),(p.replace?l.replace:l.push)(v,p.state,p)},[i,l,d,u,n])}T.createContext(null);function KS(){let{matches:n}=T.useContext(sn),i=n[n.length-1];return(i==null?void 0:i.params)??{}}function tl(n,{relative:i}={}){let{matches:l}=T.useContext(sn),{pathname:r}=ln(),u=JSON.stringify(Hf(l));return T.useMemo(()=>no(n,JSON.parse(u),r,i==="path"),[n,u,r,i])}function QS(n,i){return jg(n,i)}function jg(n,i,l){var _;Gt(Ui(),"useRoutes() may be used only in the context of a component.");let{navigator:r}=T.useContext(ze),{matches:u}=T.useContext(sn),d=u[u.length-1],f=d?d.params:{},h=d?d.pathname:"/",m=d?d.pathnameBase:"/",p=d&&d.route;{let R=p&&p.path||"";Mg(h,!p||R.endsWith("*")||R.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${h}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. - -Please change the parent to .`)}let v=ln(),x;if(i){let R=typeof i=="string"?Li(i):i;Gt(m==="/"||((_=R.pathname)==null?void 0:_.startsWith(m)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${m}" but pathname "${R.pathname}" was given in the \`location\` prop.`),x=R}else x=v;let S=x.pathname||"/",E=S;if(m!=="/"){let R=m.replace(/^\//,"").split("/");E="/"+S.replace(/^\//,"").split("/").slice(R.length).join("/")}let A=l&&l.state.matches.length?l.state.matches.map(R=>Object.assign(R,{route:l.manifest[R.route.id]||R.route})):yg(n,{pathname:E});an(p||A!=null,`No routes matched location "${x.pathname}${x.search}${x.hash}" `),an(A==null||A[A.length-1].route.element!==void 0||A[A.length-1].route.Component!==void 0||A[A.length-1].route.lazy!==void 0,`Matched leaf route at location "${x.pathname}${x.search}${x.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let w=WS(A&&A.map(R=>Object.assign({},R,{params:Object.assign({},f,R.params),pathname:tn([m,r.encodeLocation?r.encodeLocation(R.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:R.pathname]),pathnameBase:R.pathnameBase==="/"?m:tn([m,r.encodeLocation?r.encodeLocation(R.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:R.pathnameBase])})),u,l);return i&&w?T.createElement(Is.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...x},navigationType:"POP"}},w):w}function ZS(){let n=aT(),i=MS(n)?`${n.status} ${n.statusText}`:n instanceof Error?n.message:JSON.stringify(n),l=n instanceof Error?n.stack:null,r="rgba(200,200,200, 0.5)",u={padding:"0.5rem",backgroundColor:r},d={padding:"2px 4px",backgroundColor:r},f=null;return console.error("Error handled by React Router default ErrorBoundary:",n),f=T.createElement(T.Fragment,null,T.createElement("p",null,"💿 Hey developer 👋"),T.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",T.createElement("code",{style:d},"ErrorBoundary")," or"," ",T.createElement("code",{style:d},"errorElement")," prop on your route.")),T.createElement(T.Fragment,null,T.createElement("h2",null,"Unexpected Application Error!"),T.createElement("h3",{style:{fontStyle:"italic"}},i),l?T.createElement("pre",{style:u},l):null,f)}var $S=T.createElement(ZS,null),Dg=class extends T.Component{constructor(n){super(n),this.state={location:n.location,revalidation:n.revalidation,error:n.error}}static getDerivedStateFromError(n){return{error:n}}static getDerivedStateFromProps(n,i){return i.location!==n.location||i.revalidation!=="idle"&&n.revalidation==="idle"?{error:n.error,location:n.location,revalidation:n.revalidation}:{error:n.error!==void 0?n.error:i.error,location:i.location,revalidation:n.revalidation||i.revalidation}}componentDidCatch(n,i){this.props.onError?this.props.onError(n,i):console.error("React Router caught the following error during render",n)}render(){let n=this.state.error;if(this.context&&typeof n=="object"&&n&&"digest"in n&&typeof n.digest=="string"){const l=qS(n.digest);l&&(n=l)}let i=n!==void 0?T.createElement(sn.Provider,{value:this.props.routeContext},T.createElement(Gf.Provider,{value:n,children:this.props.component})):this.props.children;return this.context?T.createElement(FS,{error:n},i):i}};Dg.contextType=Cg;var Gc=new WeakMap;function FS({children:n,error:i}){let{basename:l}=T.useContext(ze);if(typeof i=="object"&&i&&"digest"in i&&typeof i.digest=="string"){let r=YS(i.digest);if(r){let u=Gc.get(i);if(u)throw u;let d=Eg(r.location,l),f=d.absoluteURL||d.to;if(kS(f))throw new Error("Invalid redirect location");if(Tg&&!Gc.get(i))if(d.isExternal||r.reloadDocument)window.location.href=f;else{const h=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(d.to,{replace:r.replace}));throw Gc.set(i,h),h}return T.createElement("meta",{httpEquiv:"refresh",content:`0;url=${f}`})}}return n}function JS({routeContext:n,match:i,children:l}){let r=T.useContext(ki);return r&&r.static&&r.staticContext&&(i.route.errorElement||i.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=i.route.id),T.createElement(sn.Provider,{value:n},l)}function WS(n,i=[],l){let r=l==null?void 0:l.state;if(n==null){if(!r)return null;if(r.errors)n=r.matches;else if(i.length===0&&!r.initialized&&r.matches.length>0)n=r.matches;else return null}let u=n,d=r==null?void 0:r.errors;if(d!=null){let v=u.findIndex(x=>x.route.id&&(d==null?void 0:d[x.route.id])!==void 0);Gt(v>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(d).join(",")}`),u=u.slice(0,Math.min(u.length,v+1))}let f=!1,h=-1;if(l&&r){f=r.renderFallback;for(let v=0;v=0?u=u.slice(0,h+1):u=[u[0]];break}}}}let m=l==null?void 0:l.onError,p=r&&m?(v,x)=>{var S,E;m(v,{location:r.location,params:((E=(S=r.matches)==null?void 0:S[0])==null?void 0:E.params)??{},pattern:OS(r.matches),errorInfo:x})}:void 0;return u.reduceRight((v,x,S)=>{let E,A=!1,w=null,_=null;r&&(E=d&&x.route.id?d[x.route.id]:void 0,w=x.route.errorElement||$S,f&&(h<0&&S===0?(Mg("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),A=!0,_=null):h===S&&(A=!0,_=x.route.hydrateFallbackElement||null)));let R=i.concat(u.slice(0,S+1)),O=()=>{let D;return E?D=w:A?D=_:x.route.Component?D=T.createElement(x.route.Component,null):x.route.element?D=x.route.element:D=v,T.createElement(JS,{match:x,routeContext:{outlet:v,matches:R,isDataRoute:r!=null},children:D})};return r&&(x.route.ErrorBoundary||x.route.errorElement||S===0)?T.createElement(Dg,{location:r.location,revalidation:r.revalidation,component:w,error:E,children:O(),routeContext:{outlet:null,matches:R,isDataRoute:!0},onError:p}):O()},null)}function Yf(n){return`${n} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function IS(n){let i=T.useContext(ki);return Gt(i,Yf(n)),i}function tT(n){let i=T.useContext(ao);return Gt(i,Yf(n)),i}function eT(n){let i=T.useContext(sn);return Gt(i,Yf(n)),i}function qf(n){let i=eT(n),l=i.matches[i.matches.length-1];return Gt(l.route.id,`${n} can only be used on routes that contain a unique "id"`),l.route.id}function nT(){return qf("useRouteId")}function aT(){var r;let n=T.useContext(Gf),i=tT("useRouteError"),l=qf("useRouteError");return n!==void 0?n:(r=i.errors)==null?void 0:r[l]}function iT(){let{router:n}=IS("useNavigate"),i=qf("useNavigate"),l=T.useRef(!1);return Ng(()=>{l.current=!0}),T.useCallback(async(u,d={})=>{an(l.current,_g),l.current&&(typeof u=="number"?await n.navigate(u):await n.navigate(u,{fromRouteId:i,...d}))},[n,i])}var Hy={};function Mg(n,i,l){!i&&!Hy[n]&&(Hy[n]=!0,an(!1,l))}T.memo(sT);function sT({routes:n,manifest:i,future:l,state:r,isStatic:u,onError:d}){return jg(n,void 0,{manifest:i,state:r,isStatic:u,onError:d})}function Gy({to:n,replace:i,state:l,relative:r}){Gt(Ui()," may be used only in the context of a component.");let{static:u}=T.useContext(ze);an(!u," must not be used on the initial render in a . This is a no-op, but you should modify your code so the is only ever rendered in response to some user interaction or state change.");let{matches:d}=T.useContext(sn),{pathname:f}=ln(),h=pa(),m=no(n,Hf(d),f,r==="path"),p=JSON.stringify(m);return T.useEffect(()=>{h(JSON.parse(p),{replace:i,state:l,relative:r})},[h,p,r,i,l]),null}function We(n){Gt(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function lT({basename:n="/",children:i=null,location:l,navigationType:r="POP",navigator:u,static:d=!1,useTransitions:f}){Gt(!Ui(),"You cannot render a inside another . You should never have more than one in your app.");let h=n.replace(/^\/*/,"/"),m=T.useMemo(()=>({basename:h,navigator:u,static:d,useTransitions:f,future:{}}),[h,u,d,f]);typeof l=="string"&&(l=Li(l));let{pathname:p="/",search:v="",hash:x="",state:S=null,key:E="default",mask:A}=l,w=T.useMemo(()=>{let _=kn(p,h);return _==null?null:{location:{pathname:_,search:v,hash:x,state:S,key:E,mask:A},navigationType:r}},[h,p,v,x,S,E,r,A]);return an(w!=null,` is not able to match the URL "${p}${v}${x}" because it does not start with the basename, so the won't render anything.`),w==null?null:T.createElement(ze.Provider,{value:m},T.createElement(Is.Provider,{children:i,value:w}))}function Yy({children:n,location:i}){return QS(of(n),i)}function of(n,i=[]){let l=[];return T.Children.forEach(n,(r,u)=>{if(!T.isValidElement(r))return;let d=[...i,u];if(r.type===T.Fragment){l.push.apply(l,of(r.props.children,d));return}Gt(r.type===We,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Gt(!r.props.index||!r.props.children,"An index route cannot have child routes.");let f={id:r.props.id||d.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(f.children=of(r.props.children,d)),l.push(f)}),l}var zr="get",Lr="application/x-www-form-urlencoded";function io(n){return typeof HTMLElement<"u"&&n instanceof HTMLElement}function rT(n){return io(n)&&n.tagName.toLowerCase()==="button"}function oT(n){return io(n)&&n.tagName.toLowerCase()==="form"}function uT(n){return io(n)&&n.tagName.toLowerCase()==="input"}function cT(n){return!!(n.metaKey||n.altKey||n.ctrlKey||n.shiftKey)}function fT(n,i){return n.button===0&&(!i||i==="_self")&&!cT(n)}var Cr=null;function dT(){if(Cr===null)try{new FormData(document.createElement("form"),0),Cr=!1}catch{Cr=!0}return Cr}var hT=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Yc(n){return n!=null&&!hT.has(n)?(an(!1,`"${n}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${Lr}"`),null):n}function mT(n,i){let l,r,u,d,f;if(oT(n)){let h=n.getAttribute("action");r=h?kn(h,i):null,l=n.getAttribute("method")||zr,u=Yc(n.getAttribute("enctype"))||Lr,d=new FormData(n)}else if(rT(n)||uT(n)&&(n.type==="submit"||n.type==="image")){let h=n.form;if(h==null)throw new Error('Cannot submit a