mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24d90bb750 | ||
|
|
c2726e6b18 | ||
|
|
a746ce9169 | ||
|
|
c00b967179 | ||
|
|
f6e749ecf9 | ||
|
|
8f5e0686c8 |
+1
-1
@@ -26,5 +26,5 @@ keywords:
|
|||||||
- web-ui
|
- web-ui
|
||||||
- agent
|
- agent
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
version: 1.2.5-rc.2
|
version: 1.2.5-rc.7
|
||||||
date-released: "2026-02-01"
|
date-released: "2026-02-01"
|
||||||
|
|||||||
@@ -1,289 +1,169 @@
|
|||||||
// import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
// import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
// import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
// import * as drizzleDb from "@/db";
|
|
||||||
// import {db} from "@/db";
|
|
||||||
// import {Backup} from "@/db/schema/07_database";
|
|
||||||
// import {and, eq} from "drizzle-orm";
|
|
||||||
// import {withUpdatedAt} from "@/db/utils";
|
|
||||||
// import {decryptedDump, getFileExtension} from "./helpers";
|
|
||||||
// import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
|
||||||
// import {storeBackupFiles} from "@/features/storages/helpers";
|
|
||||||
// import {eventEmitter} from "@/features/shared/event";
|
|
||||||
//
|
|
||||||
// export async function POST(
|
|
||||||
// request: Request,
|
|
||||||
// {params}: { params: Promise<{ agentId: string }> }
|
|
||||||
// ) {
|
|
||||||
// try {
|
|
||||||
// const contentType = request.headers.get("Content-Type");
|
|
||||||
//
|
|
||||||
// if (!contentType || !contentType.includes("multipart/form-data")) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Unsupported or missing Content-Type"},
|
|
||||||
// {status: 400}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// eventEmitter.emit('modification', {update: true});
|
|
||||||
//
|
|
||||||
// const agentId = (await params).agentId;
|
|
||||||
// const formData = await request.formData();
|
|
||||||
// const aesKeyHex = formData.get("aes_key") as string;
|
|
||||||
// const ivHex = formData.get("iv") as string;
|
|
||||||
// const generatedId = formData.get("generatedId") as string | null;
|
|
||||||
// const method = formData.get("method") as string | null;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if (!generatedId || !isUuidv4(generatedId)) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "generatedId is not a valid UUID"},
|
|
||||||
// {status: 400}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const agent = await db.query.agent.findFirst({
|
|
||||||
// where: eq(drizzleDb.schemas.agent.id, agentId),
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// if (!agent) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Agent not found"},
|
|
||||||
// {status: 404}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const database = await db.query.database.findFirst({
|
|
||||||
// where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
|
|
||||||
// with: {
|
|
||||||
// project: true,
|
|
||||||
// alertPolicies: true,
|
|
||||||
// storagePolicies: true
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// if (!database) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Database associated with generatedId not found"},
|
|
||||||
// {status: 404}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let backup: Backup | null | undefined = null;
|
|
||||||
//
|
|
||||||
// if (method === "automatic") {
|
|
||||||
// [backup] = await db
|
|
||||||
// .insert(drizzleDb.schemas.backup)
|
|
||||||
// .values({
|
|
||||||
// status: 'ongoing',
|
|
||||||
// databaseId: database.id,
|
|
||||||
// })
|
|
||||||
// .returning();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if (!backup) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Unable to create an automatic backup"},
|
|
||||||
// {status: 500}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// backup = await db.query.backup.findFirst({
|
|
||||||
// where: and(
|
|
||||||
// eq(drizzleDb.schemas.backup.status, 'ongoing'),
|
|
||||||
// eq(drizzleDb.schemas.backup.databaseId, database.id),
|
|
||||||
// ),
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if (!backup) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Unable to find the corresponding backup"},
|
|
||||||
// {status: 404}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const status = formData.get("status") as string | null;
|
|
||||||
//
|
|
||||||
// if (status === "success") {
|
|
||||||
// const file = formData.get("file") as File | null;
|
|
||||||
// const extension = formData.get("extension") as string | null;
|
|
||||||
// if (!aesKeyHex || !ivHex) {
|
|
||||||
// return NextResponse.json({error: "Missing fields"}, {status: 400});
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// if (!file) {
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "File is required for successful backup"},
|
|
||||||
// {status: 400}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// const fileSizeBytes = file.size;
|
|
||||||
// // const fileExtension = '.' + (file.name.split('.').pop()?.toLowerCase() || '');
|
|
||||||
// const fileExtension = extension ? extension : getFileExtension(database.dbms)
|
|
||||||
// const decryptedFile = await decryptedDump(file, aesKeyHex, ivHex, fileExtension);
|
|
||||||
// const uuid = uuidv4();
|
|
||||||
// const fileName = `${uuid}${fileExtension}`;
|
|
||||||
// const buffer = Buffer.from(await decryptedFile.arrayBuffer());
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// const storageResults = await storeBackupFiles(backup, database, buffer, fileName)
|
|
||||||
// eventEmitter.emit('modification', {update: true});
|
|
||||||
//
|
|
||||||
// await sendNotificationsBackupRestore(database, "success_backup");
|
|
||||||
//
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {
|
|
||||||
// message: "Backup successfully uploaded",
|
|
||||||
// },
|
|
||||||
// {status: 200}
|
|
||||||
// );
|
|
||||||
// } 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 NextResponse.json(
|
|
||||||
// {
|
|
||||||
// message: "Backup successfully updated with status failed",
|
|
||||||
// },
|
|
||||||
// {status: 200}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error in POST handler:", error);
|
|
||||||
// return NextResponse.json(
|
|
||||||
// {error: "Internal server error"},
|
|
||||||
// {status: 500}
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
import { v4 as uuidv4 } from "uuid";
|
|
||||||
import { and, eq } from "drizzle-orm";
|
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import { db } from "@/db";
|
import {db} from "@/db";
|
||||||
import { isUuidv4 } from "@/utils/verify-uuid";
|
import {Backup} from "@/db/schema/07_database";
|
||||||
import uploadTempFileToProviders, { createDecryptionStream } from "@/features/api/upload/helpers/common";
|
import {and, eq} from "drizzle-orm";
|
||||||
import { getFileExtension, saveStreamToTempFile } from "@/features/api/upload/helpers/file";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import { Backup } from "@/db/schema/07_database";
|
import {decryptedDump, getFileExtension} from "./helpers";
|
||||||
import { withUpdatedAt } from "@/db/utils";
|
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||||
import { eventEmitter } from "@/features/shared/event";
|
import {storeBackupFiles} from "@/features/storages/helpers";
|
||||||
import { sendNotificationsBackupRestore } from "@/features/notifications/helpers";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
import {Readable} from "node:stream";
|
|
||||||
|
|
||||||
export async function POST(request: Request, { params }: { params: Promise<{ agentId: string }> }) {
|
export async function POST(
|
||||||
|
request: Request,
|
||||||
|
{params}: { params: Promise<{ agentId: string }> }
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const agentId = (await params).agentId;
|
const contentType = request.headers.get("Content-Type");
|
||||||
const headers = request.headers;
|
|
||||||
|
|
||||||
const generatedId = headers.get("x-generated-id");
|
if (!contentType || !contentType.includes("multipart/form-data")) {
|
||||||
const status = headers.get("x-status");
|
return NextResponse.json(
|
||||||
const encryptedAesKeyHex = headers.get("x-aes-key");
|
{error: "Unsupported or missing Content-Type"},
|
||||||
const ivHex = headers.get("x-iv");
|
{status: 400}
|
||||||
const method = headers.get("x-method") ?? "manual";
|
);
|
||||||
const extension = headers.get("x-extension");
|
|
||||||
|
|
||||||
if (!agentId || !generatedId || !status || !encryptedAesKeyHex || !ivHex) {
|
|
||||||
return NextResponse.json({ error: "Missing required headers/params" }, { status: 400 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isUuidv4(generatedId)) {
|
eventEmitter.emit('modification', {update: true});
|
||||||
return NextResponse.json({ error: "generatedId is not a valid UUID" }, { status: 400 });
|
|
||||||
|
const agentId = (await params).agentId;
|
||||||
|
const formData = await request.formData();
|
||||||
|
const aesKeyHex = formData.get("aes_key") as string;
|
||||||
|
const ivHex = formData.get("iv") as string;
|
||||||
|
const generatedId = formData.get("generatedId") as string | null;
|
||||||
|
const method = formData.get("method") as string | null;
|
||||||
|
|
||||||
|
|
||||||
|
if (!generatedId || !isUuidv4(generatedId)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{error: "generatedId is not a valid UUID"},
|
||||||
|
{status: 400}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (!agent) {
|
||||||
return NextResponse.json({ error: "Agent not found" }, { status: 404 });
|
return NextResponse.json(
|
||||||
|
{error: "Agent not found"},
|
||||||
|
{status: 404}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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: { project: true, storagePolicies: true },
|
with: {
|
||||||
|
project: true,
|
||||||
|
alertPolicies: true,
|
||||||
|
storagePolicies: true
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!database) {
|
if (!database) {
|
||||||
return NextResponse.json({ error: "Database not found" }, { status: 404 });
|
return NextResponse.json(
|
||||||
|
{error: "Database associated with generatedId not found"},
|
||||||
|
{status: 404}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let backup: Backup | null | undefined = null;
|
let backup: Backup | null | undefined = null;
|
||||||
|
|
||||||
if (method === "automatic") {
|
if (method === "automatic") {
|
||||||
[backup] = await db
|
[backup] = await db
|
||||||
.insert(drizzleDb.schemas.backup)
|
.insert(drizzleDb.schemas.backup)
|
||||||
.values({ status: "ongoing", databaseId: database.id })
|
.values({
|
||||||
|
status: 'ongoing',
|
||||||
|
databaseId: database.id,
|
||||||
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
|
||||||
|
if (!backup) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{error: "Unable to create an automatic backup"},
|
||||||
|
{status: 500}
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
backup = await db.query.backup.findFirst({
|
backup = await db.query.backup.findFirst({
|
||||||
where: and(
|
where: and(
|
||||||
|
eq(drizzleDb.schemas.backup.status, 'ongoing'),
|
||||||
eq(drizzleDb.schemas.backup.databaseId, database.id),
|
eq(drizzleDb.schemas.backup.databaseId, database.id),
|
||||||
eq(drizzleDb.schemas.backup.status, "ongoing")
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (!backup) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{error: "Unable to find the corresponding backup"},
|
||||||
|
{status: 404}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backup) {
|
const status = formData.get("status") as string | null;
|
||||||
return NextResponse.json({ error: "Backup not found" }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status === "success") {
|
if (status === "success") {
|
||||||
|
const file = formData.get("file") as File | null;
|
||||||
const decipher = createDecryptionStream(encryptedAesKeyHex, ivHex);
|
const extension = formData.get("extension") as string | null;
|
||||||
const fileExt = extension || getFileExtension(database.dbms);
|
if (!aesKeyHex || !ivHex) {
|
||||||
const fileName = `${uuidv4()}${fileExt}`;
|
return NextResponse.json({error: "Missing fields"}, {status: 400});
|
||||||
|
|
||||||
// const nodeStream = webStreamToNode(request.body as any);
|
|
||||||
|
|
||||||
// const tmpPath = await new Promise<string | null>((resolve, reject) => {
|
|
||||||
// pipeline(nodeStream, decipher, async (err) => {
|
|
||||||
// if (err) return reject(err);
|
|
||||||
// try {
|
|
||||||
// const path = await saveStreamToTempFile(decipher, fileName);
|
|
||||||
// resolve(path);
|
|
||||||
// } catch (e) {
|
|
||||||
// reject(e);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
const tmpPath = await saveStreamToTempFile(decipher, fileName);
|
|
||||||
|
|
||||||
if (!tmpPath) {
|
|
||||||
return NextResponse.json({ error: "Unable to save temporary backup file" }, { status: 500 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadTempFileToProviders(backup, database, tmpPath, fileName);
|
|
||||||
|
|
||||||
return NextResponse.json({ success: true });
|
if (!file) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{error: "File is required for successful backup"},
|
||||||
|
{status: 400}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const fileSizeBytes = file.size;
|
||||||
|
// const fileExtension = '.' + (file.name.split('.').pop()?.toLowerCase() || '');
|
||||||
|
const fileExtension = extension ? extension : getFileExtension(database.dbms)
|
||||||
|
const decryptedFile = await decryptedDump(file, aesKeyHex, ivHex, fileExtension);
|
||||||
|
const uuid = uuidv4();
|
||||||
|
const fileName = `${uuid}${fileExtension}`;
|
||||||
|
const buffer = Buffer.from(await decryptedFile.arrayBuffer());
|
||||||
|
|
||||||
|
|
||||||
|
const storageResults = await storeBackupFiles(backup, database, buffer, fileName)
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
|
await sendNotificationsBackupRestore(database, "success_backup");
|
||||||
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
message: "Backup successfully uploaded",
|
||||||
|
},
|
||||||
|
{status: 200}
|
||||||
|
);
|
||||||
} 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");
|
||||||
|
|
||||||
return NextResponse.json({ message: "Backup updated with status failed" }, { status: 200 });
|
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
message: "Backup successfully updated with status failed",
|
||||||
|
},
|
||||||
|
{status: 200}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (error) {
|
||||||
console.error("Upload error:", err);
|
console.error("Error in POST handler:", error);
|
||||||
return NextResponse.json({ error: "Upload failed", detail: err.message }, { status: 500 });
|
return NextResponse.json(
|
||||||
|
{error: "Internal server error"},
|
||||||
|
{status: 500}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function webStreamToNode(stream: ReadableStream<Uint8Array>) {
|
|
||||||
return Readable.fromWeb(stream);
|
|
||||||
}
|
|
||||||
@@ -84,8 +84,8 @@ RUN chown -R nextjs:nodejs /app/private
|
|||||||
RUN chown -R nextjs:nodejs /app/public
|
RUN chown -R nextjs:nodejs /app/public
|
||||||
|
|
||||||
COPY --from=builder /app/next.config.ts ./
|
COPY --from=builder /app/next.config.ts ./
|
||||||
#COPY --from=builder /app/server ./server
|
COPY --from=builder /app/server ./server
|
||||||
#COPY --from=builder /app/src ./src
|
COPY --from=builder /app/src ./src
|
||||||
|
|
||||||
COPY --from=builder /app/portabase.config.ts ./
|
COPY --from=builder /app/portabase.config.ts ./
|
||||||
COPY --from=builder /app/drizzle.config.ts ./
|
COPY --from=builder /app/drizzle.config.ts ./
|
||||||
@@ -93,7 +93,7 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
COPY --chown=nextjs:nodejs src/db ./src/db
|
COPY --chown=nextjs:nodejs src/db ./src/db
|
||||||
|
|
||||||
#COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ else
|
|||||||
echo "[WARN] No TZ provided, using default container timezone"
|
echo "[WARN] No TZ provided, using default container timezone"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#pnpm run start
|
pnpm run start
|
||||||
node server.js
|
#node server.js
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|
||||||
|
|||||||
@@ -41,13 +41,11 @@ const nextConfig: NextConfig = {
|
|||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
experimental: {
|
experimental: {
|
||||||
serverActions: {
|
serverActions: {
|
||||||
bodySizeLimit: "10gb",
|
bodySizeLimit: "10gb",
|
||||||
},
|
},
|
||||||
proxyClientMaxBodySize: '10gb',
|
proxyClientMaxBodySize: '10gb',
|
||||||
|
|
||||||
},
|
},
|
||||||
async headers() {
|
async headers() {
|
||||||
return [
|
return [
|
||||||
|
|||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "portabase",
|
"name": "portabase",
|
||||||
"version": "1.2.5-rc.2",
|
"version": "1.2.5-rc.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack -p 8887",
|
"dev": "NODE_ENV=development tsx watch server/server.ts",
|
||||||
"build": "next build --experimental-build-mode compile",
|
"build": "next build --experimental-build-mode compile",
|
||||||
"start": "next start",
|
"start": "NODE_ENV=production tsx server/server.ts",
|
||||||
|
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"email": "email dev --dir ./src/components/emails",
|
"email": "email dev --dir ./src/components/emails",
|
||||||
|
|||||||
Generated
+1246
-2199
File diff suppressed because it is too large
Load Diff
+19
-9
@@ -1,6 +1,7 @@
|
|||||||
import next from "next";
|
import next from "next";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import {mountApi} from "./api";
|
import {mountApi} from "./api";
|
||||||
|
import http from "http";
|
||||||
|
|
||||||
const port = Number(process.env.PORT) || 8887;
|
const port = Number(process.env.PORT) || 8887;
|
||||||
const dev = process.env.NODE_ENV !== "production";
|
const dev = process.env.NODE_ENV !== "production";
|
||||||
@@ -17,11 +18,17 @@ async function start() {
|
|||||||
|
|
||||||
await nextApp.prepare();
|
await nextApp.prepare();
|
||||||
|
|
||||||
const server = express();
|
const app = express();
|
||||||
|
|
||||||
mountApi(server);
|
app.use((req, res, next) => {
|
||||||
|
req.setTimeout(0);
|
||||||
|
res.setTimeout(0);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
server.use((req, res, next) => {
|
mountApi(app);
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
if (req.path.startsWith('/services/v1')) return next();
|
if (req.path.startsWith('/services/v1')) return next();
|
||||||
handle(req, res).catch((err) => {
|
handle(req, res).catch((err) => {
|
||||||
console.error('Next.js App Router error:', err);
|
console.error('Next.js App Router error:', err);
|
||||||
@@ -29,13 +36,16 @@ async function start() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const server = http.createServer(app);
|
||||||
|
|
||||||
|
server.setTimeout(0);
|
||||||
|
server.headersTimeout = 0;
|
||||||
|
server.requestTimeout = 0;
|
||||||
|
server.keepAliveTimeout = 0;
|
||||||
|
|
||||||
server.listen(port, "0.0.0.0", () => {
|
server.listen(port, "0.0.0.0", () => {
|
||||||
console.log(
|
console.log(`NEXT APP → http://localhost:${port}`);
|
||||||
`NEXT APP → http://localhost:${port}`
|
console.log(`API → http://localhost:${port}/services/v1`);
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`API → http://localhost:${port}/services/v1`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import express, {Router} from "express";
|
import express, { Router } from "express";
|
||||||
import uploadRouter from "./upload";
|
import uploadRouter from "./upload";
|
||||||
import {loggingMiddleware} from "@/features/api/middleware";
|
import { loggingMiddleware } from "@/features/api/middleware";
|
||||||
|
|
||||||
const router: Router = express.Router();
|
const router: Router = express.Router();
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ router.post("/:agentId", async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const tmpPath = await saveStreamToTempFile(decryptedStream, fileName);
|
const tmpPath = await saveStreamToTempFile(decryptedStream, fileName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!tmpPath) {
|
if (!tmpPath) {
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
error: "Unable to save tmp backup file",
|
error: "Unable to save tmp backup file",
|
||||||
|
|||||||
Reference in New Issue
Block a user