chore(release): 1.2.5-rc.8

This commit is contained in:
charlesgauthereau
2026-02-01 22:04:07 +01:00
parent 24d90bb750
commit 614a9e057c
3 changed files with 175 additions and 103 deletions
+1 -1
View File
@@ -26,5 +26,5 @@ keywords:
- web-ui - web-ui
- agent - agent
license: Apache-2.0 license: Apache-2.0
version: 1.2.5-rc.7 version: 1.2.5-rc.8
date-released: "2026-02-01" date-released: "2026-02-01"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "portabase", "name": "portabase",
"version": "1.2.5-rc.7", "version": "1.2.5-rc.8",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "NODE_ENV=development tsx watch server/server.ts", "dev": "NODE_ENV=development tsx watch server/server.ts",
+136 -64
View File
@@ -13,8 +13,116 @@ import {getFileExtension, saveStreamToTempFile} from "@/features/api/upload/help
const router: Router = express.Router(); const router: Router = express.Router();
// router.post("/:agentId", async (req: Request, res: Response) => {
// try {
// const agentId = req.params.agentId as string | undefined;
// const generatedId = req.headers["x-generated-id"] as string | undefined;
// const status = req.headers["x-status"] as string | undefined;
// const encryptedAesKeyHex = req.headers["x-aes-key"] as string | undefined;
// const ivHex = req.headers["x-iv"] as string | undefined;
// const method = (req.headers["x-method"] as string) ?? "manual";
// const extension = req.headers["x-extension"] as string | undefined;
//
//
// if (!generatedId || !encryptedAesKeyHex || !ivHex || !agentId || !status) {
// return res.status(400).json({error: "Missing required headers/params"});
// }
//
// if (!isUuidv4(generatedId)) {
// return res.status(400).json({error: "generatedId is not a valid UUID"});
// }
//
// const agent = await db.query.agent.findFirst({
// where: eq(drizzleDb.schemas.agent.id, agentId),
// });
//
// if (!agent) {
// return res.status(404).json({error: "Agent not found"});
// }
//
//
// const database = await db.query.database.findFirst({
// where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
// with: {
// project: true,
// storagePolicies: true,
// },
// });
//
// if (!database) {
// return res.status(404).json({error: "Database not found"});
// }
//
// let backup: Backup | null | undefined = null;
//
// if (method === "automatic") {
// [backup] = await db
// .insert(drizzleDb.schemas.backup)
// .values({
// status: "ongoing",
// databaseId: database.id,
// })
// .returning();
// } else {
// backup = await db.query.backup.findFirst({
// where: and(
// eq(drizzleDb.schemas.backup.databaseId, database.id),
// eq(drizzleDb.schemas.backup.status, "ongoing")
// ),
// });
// }
//
// if (!backup) {
// return res.status(404).json({error: "Backup not found"});
// }
//
//
// if (status === "success") {
//
// const decipher = createDecryptionStream(encryptedAesKeyHex, ivHex);
//
// const fileExt = extension || getFileExtension(database.dbms);
// const fileName = `${uuidv4()}${fileExt}`;
//
// const decryptedStream = req.pipe(decipher);
//
// const tmpPath = await saveStreamToTempFile(decryptedStream, fileName);
//
//
//
//
// if (!tmpPath) {
// return res.status(500).json({
// error: "Unable to save tmp backup file",
// });
// }
//
// uploadTempFileToProviders(backup, database, tmpPath, fileName);
//
// return res.json({success: true});
// } else {
// await db
// .update(drizzleDb.schemas.backup)
// .set(withUpdatedAt({status: 'failed'}))
// .where(eq(drizzleDb.schemas.backup.id, backup.id));
//
// eventEmitter.emit('modification', {update: true});
//
// await sendNotificationsBackupRestore(database, "error_backup");
//
// return res.status(200).json({
// error: "Backup successfully updated with status failed",
// });
// }
// } catch (err: any) {
// console.error("Upload error:", err);
// return res.status(500).json({
// error: "Upload failed",
// detail: err.message,
// });
// }
// });
router.post("/:agentId", async (req: Request, res: Response) => { router.post("/:agentId", async (req: Request, res: Response) => {
try {
const agentId = req.params.agentId as string | undefined; const agentId = req.params.agentId as string | undefined;
const generatedId = req.headers["x-generated-id"] as string | undefined; const generatedId = req.headers["x-generated-id"] as string | undefined;
const status = req.headers["x-status"] as string | undefined; const status = req.headers["x-status"] as string | undefined;
@@ -23,46 +131,25 @@ router.post("/:agentId", async (req: Request, res: Response) => {
const method = (req.headers["x-method"] as string) ?? "manual"; const method = (req.headers["x-method"] as string) ?? "manual";
const extension = req.headers["x-extension"] as string | undefined; const extension = req.headers["x-extension"] as string | undefined;
if (!generatedId || !encryptedAesKeyHex || !ivHex || !agentId || !status) { if (!generatedId || !encryptedAesKeyHex || !ivHex || !agentId || !status) {
return res.status(400).json({error: "Missing required headers/params"}); return res.status(400).json({error: "Missing required headers/params"});
} }
if (!isUuidv4(generatedId)) { if (!isUuidv4(generatedId)) {
return res.status(400).json({error: "generatedId is not a valid UUID"}); return res.status(400).json({error: "generatedId is not a valid UUID"});
} }
const agent = await db.query.agent.findFirst({ const agent = await db.query.agent.findFirst({ where: eq(drizzleDb.schemas.agent.id, agentId) });
where: eq(drizzleDb.schemas.agent.id, agentId), if (!agent) return res.status(404).json({error: "Agent not found"});
});
if (!agent) {
return res.status(404).json({error: "Agent not found"});
}
const database = await db.query.database.findFirst({ const database = await db.query.database.findFirst({
where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId), where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
with: { with: { project: true, storagePolicies: true },
project: true,
storagePolicies: true,
},
}); });
if (!database) return res.status(404).json({error: "Database not found"});
if (!database) { let backup: Backup | null = null;
return res.status(404).json({error: "Database not found"});
}
let backup: Backup | null | undefined = null;
if (method === "automatic") { if (method === "automatic") {
[backup] = await db [backup] = await db.insert(drizzleDb.schemas.backup).values({ status: "ongoing", databaseId: database.id }).returning();
.insert(drizzleDb.schemas.backup)
.values({
status: "ongoing",
databaseId: database.id,
})
.returning();
} else { } else {
backup = await db.query.backup.findFirst({ backup = await db.query.backup.findFirst({
where: and( where: and(
@@ -71,57 +158,42 @@ router.post("/:agentId", async (req: Request, res: Response) => {
), ),
}); });
} }
if (!backup) return res.status(404).json({error: "Backup not found"});
if (!backup) { res.status(202).json({success: true, message: "Backup received, processing in background"});
return res.status(404).json({error: "Backup not found"});
}
(async () => {
try {
if (status === "success") { if (status === "success") {
const decipher = createDecryptionStream(encryptedAesKeyHex!, ivHex!);
const decipher = createDecryptionStream(encryptedAesKeyHex, ivHex);
const fileExt = extension || getFileExtension(database.dbms); const fileExt = extension || getFileExtension(database.dbms);
const fileName = `${uuidv4()}${fileExt}`; const fileName = `${uuidv4()}${fileExt}`;
const decryptedStream = req.pipe(decipher); const decryptedStream = req.pipe(decipher);
const tmpPath = await saveStreamToTempFile(decryptedStream, fileName); const tmpPath = await saveStreamToTempFile(decryptedStream, fileName);
if (!tmpPath) throw new Error("Unable to save tmp backup file");
await uploadTempFileToProviders(backup!, database, tmpPath, fileName);
if (!tmpPath) {
return res.status(500).json({
error: "Unable to save tmp backup file",
});
}
uploadTempFileToProviders(backup, database, tmpPath, fileName);
return res.json({success: true});
} else { } else {
await db await db.update(drizzleDb.schemas.backup)
.update(drizzleDb.schemas.backup)
.set(withUpdatedAt({status: 'failed'})) .set(withUpdatedAt({status: 'failed'}))
.where(eq(drizzleDb.schemas.backup.id, backup.id)); .where(eq(drizzleDb.schemas.backup.id, backup!.id));
eventEmitter.emit('modification', {update: true}); eventEmitter.emit('modification', {update: true});
await sendNotificationsBackupRestore(database, "error_backup"); await sendNotificationsBackupRestore(database, "error_backup");
}
} catch (err) {
console.error("Background backup processing failed:", err);
try {
await db.update(drizzleDb.schemas.backup)
.set(withUpdatedAt({status: 'failed'}))
.where(eq(drizzleDb.schemas.backup.id, backup!.id));
} catch (_) {
}
}
})();
});
return res.status(200).json({
error: "Backup successfully updated with status failed",
});
}
} catch (err: any) {
console.error("Upload error:", err);
return res.status(500).json({
error: "Upload failed",
detail: err.message,
});
}
});
export default router; export default router;