mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31cbd52703 | ||
|
|
dd85f7a25d | ||
|
|
203c25aabe | ||
|
|
41b1c89283 | ||
|
|
180ea21041 | ||
|
|
e1c0fc6917 |
@@ -58,3 +58,6 @@ AUTH_PASSKEY_ENABLED=true
|
|||||||
|
|
||||||
# Retention
|
# Retention
|
||||||
RETENTION_CRON="* * * * *"
|
RETENTION_CRON="* * * * *"
|
||||||
|
|
||||||
|
TRUSTED_DOMAINS="http://localhost:8887, http://localhost:3055, http://localhost:3056"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -31,5 +31,5 @@ keywords:
|
|||||||
- web-ui
|
- web-ui
|
||||||
- agent
|
- agent
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
version: 1.9.2
|
version: 1.9.5
|
||||||
date-released: '2026-03-02'
|
date-released: '2026-03-02'
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { NextResponse } from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import { eq } from "drizzle-orm";
|
import {eq} from "drizzle-orm";
|
||||||
import { db } from "@/db";
|
import {db} from "@/db";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/backup/helpers"});
|
||||||
|
|
||||||
export function withAgentCheck(handler: Function) {
|
export function withAgentCheck(handler: Function) {
|
||||||
return async (request: Request, context: { params: Promise<{ agentId: string }> }) => {
|
return async (request: Request, context: { params: Promise<{ agentId: string }> }) => {
|
||||||
@@ -14,23 +17,22 @@ export function withAgentCheck(handler: Function) {
|
|||||||
|
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Agent not found" },
|
{error: "Agent not found"},
|
||||||
{ status: 404 }
|
{status: 404}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler(request, { ...context, agent });
|
return handler(request, {...context, agent});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error in agent middleware:", err);
|
log.error({error: err, name: "withAgentCheck"}, "Error in agent middleware");
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Internal server error" },
|
{error: "Internal server error"},
|
||||||
{ status: 500 }
|
{status: 500}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function getDatabaseOrThrow(generatedId: string) {
|
export async function getDatabaseOrThrow(generatedId: string) {
|
||||||
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),
|
||||||
@@ -43,8 +45,8 @@ export async function getDatabaseOrThrow(generatedId: string) {
|
|||||||
|
|
||||||
if (!database) {
|
if (!database) {
|
||||||
throw NextResponse.json(
|
throw NextResponse.json(
|
||||||
{ error: "Database associated with generatedId not found" },
|
{error: "Database associated with generatedId not found"},
|
||||||
{ status: 404 }
|
{status: 404}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import {withUpdatedAt} from "@/db/utils";
|
|||||||
import {eventEmitter} from "@/features/shared/event";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||||
import {EventKind} from "@/features/notifications/types";
|
import {EventKind} from "@/features/notifications/types";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/backup/route"});
|
||||||
|
|
||||||
export type BodyPost = {
|
export type BodyPost = {
|
||||||
method: "manual" | "automatic"
|
method: "manual" | "automatic"
|
||||||
@@ -77,7 +80,6 @@ export const POST = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
eventEmitter.emit('modification', {update: true});
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -88,7 +90,7 @@ export const POST = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
{status: 200}
|
{status: 200}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in POST for INIT backup:", error);
|
log.error({error: error}, "Error in POST for INIT backup");
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Internal server error"},
|
{error: "Internal server error"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
@@ -102,7 +104,7 @@ export const PATCH = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
const body: BodyPatch = await request.json();
|
const body: BodyPatch = await request.json();
|
||||||
console.log("body", body);
|
log.info({data: body}, "Body from PATH in backup route");
|
||||||
|
|
||||||
const status = body.status
|
const status = body.status
|
||||||
const backupId = body.backupId
|
const backupId = body.backupId
|
||||||
@@ -142,9 +144,7 @@ export const PATCH = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
{status: 200}
|
{status: 200}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
log.error({error: error}, "Error in PATCH backup")
|
||||||
|
|
||||||
console.error("Error in PATCH backup:", error);
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Internal server error"},
|
{error: "Internal server error"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import {db} from "@/db";
|
|||||||
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/backup/upload/init"});
|
||||||
|
|
||||||
export type Body = {
|
export type Body = {
|
||||||
generatedId: string
|
generatedId: string
|
||||||
@@ -18,7 +21,7 @@ export const POST = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
try {
|
try {
|
||||||
const body: Body = await request.json();
|
const body: Body = await request.json();
|
||||||
|
|
||||||
console.log("body", body);
|
log.info({data: body}, "Body for backup upload init");
|
||||||
|
|
||||||
const generatedId = body.generatedId;
|
const generatedId = body.generatedId;
|
||||||
const storageChannelId = body.storageChannelId;
|
const storageChannelId = body.storageChannelId;
|
||||||
@@ -66,7 +69,7 @@ export const POST = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
{status: 200}
|
{status: 200}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in POST for INIT backup:", error);
|
log.error({error: error}, "Error in POST for INIT backup");
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Internal server error"},
|
{error: "Internal server error"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import {db as dbClient, db} from "@/db";
|
|||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/backup/upload/status"});
|
||||||
|
|
||||||
export type Body = {
|
export type Body = {
|
||||||
generatedId: string
|
generatedId: string
|
||||||
@@ -27,8 +30,7 @@ export const PATCH = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
const backupStorageId = body.backupStorageId;
|
const backupStorageId = body.backupStorageId;
|
||||||
const backupId = body.backupId;
|
const backupId = body.backupId;
|
||||||
|
|
||||||
|
log.info({data: body}, "Body for backup upload status");
|
||||||
console.log("body", body);
|
|
||||||
|
|
||||||
const database = await getDatabaseOrThrow(generatedId);
|
const database = await getDatabaseOrThrow(generatedId);
|
||||||
|
|
||||||
@@ -85,7 +87,7 @@ export const PATCH = withAgentCheck(async (request: Request, {params, agent}: {
|
|||||||
{status: 200}
|
{status: 200}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in POST for INIT backup:", error);
|
log.error({error: error},"Error in POST for INIT backup");
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Internal server error"},
|
{error: "Internal server error"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import * as drizzleDb from "@/db";
|
|||||||
import {db} from "@/db";
|
import {db} from "@/db";
|
||||||
import {and, eq} from "drizzle-orm";
|
import {and, eq} from "drizzle-orm";
|
||||||
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/restore"});
|
||||||
|
|
||||||
export type BodyResultRestore = {
|
export type BodyResultRestore = {
|
||||||
generatedId: string
|
generatedId: string
|
||||||
@@ -70,10 +72,9 @@ export async function POST(
|
|||||||
message: "Restoration successfully updated"
|
message: "Restoration successfully updated"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Response.json(response, {status: 200})
|
return Response.json(response, {status: 200})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in POST handler:', error);
|
log.error({error: error}, "Error in POST handler")
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: 'Internal server error'},
|
{error: 'Internal server error'},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {NextResponse} from "next/server";
|
|||||||
import {Body} from "./route";
|
import {Body} from "./route";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {Agent} from "@/db/schema/08_agent";
|
import {Agent} from "@/db/schema/08_agent";
|
||||||
import {Database, DatabaseWith} from "@/db/schema/07_database";
|
import {DatabaseWith} from "@/db/schema/07_database";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {db, db as dbClient} from "@/db";
|
import {db, db as dbClient} from "@/db";
|
||||||
import {and, eq, inArray} from "drizzle-orm";
|
import {and, eq, inArray} from "drizzle-orm";
|
||||||
@@ -11,6 +11,9 @@ import {withUpdatedAt} from "@/db/utils";
|
|||||||
import type {StorageInput} from "@/features/storages/types";
|
import type {StorageInput} from "@/features/storages/types";
|
||||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
import {Setting} from "@/db/schema/01_setting";
|
import {Setting} from "@/db/schema/01_setting";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/status/helpers"});
|
||||||
|
|
||||||
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date, settings: Setting) {
|
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date, settings: Setting) {
|
||||||
const databasesResponse = [];
|
const databasesResponse = [];
|
||||||
@@ -56,7 +59,7 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dbmsEnumSchema.safeParse(db.dbms).success) {
|
if (!dbmsEnumSchema.safeParse(db.dbms).success) {
|
||||||
console.log(`Database type not available: ${db.dbms}`);
|
log.error({name: "handleDatabases"},`Database type not available: ${db.dbms}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +88,6 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
|
|||||||
date: lastContact
|
date: lastContact
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const storages = await getDatabaseStorageChannels(databaseCreated.id)
|
const storages = await getDatabaseStorageChannels(databaseCreated.id)
|
||||||
|
|
||||||
databasesResponse.push(formatDatabase(databaseCreated, backupAction, restoreAction, urlBackup, storages, null));
|
databasesResponse.push(formatDatabase(databaseCreated, backupAction, restoreAction, urlBackup, storages, null));
|
||||||
@@ -185,11 +187,11 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
|
|||||||
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
|
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
|
||||||
|
|
||||||
const errorMessage = "Failed to get backup URL";
|
const errorMessage = "Failed to get backup URL";
|
||||||
console.error("Restoration failed: ", errorMessage);
|
log.error({error: errorMessage, name: "handleDatabases"}, "Restoration failed");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Restoration crashed unexpectedly:", err);
|
log.error({error: err, name: "handleDatabases"}, "Restoration crashed unexpectedly");
|
||||||
await dbClient
|
await dbClient
|
||||||
.update(drizzleDb.schemas.restoration)
|
.update(drizzleDb.schemas.restoration)
|
||||||
.set({status: "failed"})
|
.set({status: "failed"})
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ import {EDbmsSchema} from "@/db/schema/types";
|
|||||||
import {eq} from "drizzle-orm";
|
import {eq} from "drizzle-orm";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {logger} from "@/lib/logger";
|
||||||
import {notFound} from "next/navigation";
|
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/agent/status/route"});
|
||||||
|
|
||||||
|
|
||||||
export type databaseAgent = {
|
export type databaseAgent = {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -28,14 +31,14 @@ export async function POST(
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const agentId = (await params).agentId
|
const agentId = (await params).agentId
|
||||||
console.log(agentId)
|
log.info(`Agent ID: ${agentId}`)
|
||||||
const body: Body = await request.json();
|
const body: Body = await request.json();
|
||||||
const lastContact = new Date();
|
const lastContact = new Date();
|
||||||
let message: string
|
let message: string
|
||||||
|
|
||||||
if (!isUuidv4(agentId)) {
|
if (!isUuidv4(agentId)) {
|
||||||
message = "agentId is not a valid uuid"
|
message = "agentId is not a valid uuid"
|
||||||
console.error(message)
|
log.error({error: message}, "An error occurred")
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "agentId is not a valid uuid"},
|
{error: "agentId is not a valid uuid"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
@@ -56,7 +59,6 @@ export async function POST(
|
|||||||
return NextResponse.json({error: "An error occured"}, {status: 404})
|
return NextResponse.json({error: "An error occured"}, {status: 404})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const databasesResponse = await handleDatabases(body, agent, lastContact, settings)
|
const databasesResponse = await handleDatabases(body, agent, lastContact, settings)
|
||||||
|
|
||||||
await db
|
await db
|
||||||
@@ -85,10 +87,9 @@ export async function POST(
|
|||||||
databases: databasesResponse
|
databases: databasesResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Response.json(response)
|
return Response.json(response)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in POST handler:', error);
|
log.error({error: error}, "Error in POST handler")
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: 'Internal server error'},
|
{error: 'Internal server error'},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import {auth} from "@/lib/auth/auth";
|
|||||||
import {headers} from "next/headers";
|
import {headers} from "next/headers";
|
||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {eventEmitter} from "@/features/shared/event";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/events"});
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
|
|
||||||
@@ -16,9 +19,9 @@ export async function GET(request: Request) {
|
|||||||
return new Response(
|
return new Response(
|
||||||
new ReadableStream({
|
new ReadableStream({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
console.log('Stream started');
|
log.info("Stream started");
|
||||||
const handleModification = (data: any) => {
|
const handleModification = (data: any) => {
|
||||||
console.log('Modification event triggered:', data);
|
log.info({data: data},"Modification event triggered");
|
||||||
controller.enqueue(`event: modification\n`);
|
controller.enqueue(`event: modification\n`);
|
||||||
controller.enqueue(`data: ${JSON.stringify(data)}\n\n`);
|
controller.enqueue(`data: ${JSON.stringify(data)}\n\n`);
|
||||||
};
|
};
|
||||||
@@ -26,7 +29,7 @@ export async function GET(request: Request) {
|
|||||||
eventEmitter.on('modification', handleModification);
|
eventEmitter.on('modification', handleModification);
|
||||||
|
|
||||||
request.signal.addEventListener('abort', () => {
|
request.signal.addEventListener('abort', () => {
|
||||||
console.log('Client disconnected');
|
log.info("Client disconnected");
|
||||||
controller.close();
|
controller.close();
|
||||||
eventEmitter.off('modification', handleModification);
|
eventEmitter.off('modification', handleModification);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import path from "path";
|
|||||||
import type {StorageInput} from "@/features/storages/types";
|
import type {StorageInput} from "@/features/storages/types";
|
||||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
import {Readable} from "node:stream";
|
import {Readable} from "node:stream";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/files/backups"});
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
request: Request,
|
request: Request,
|
||||||
@@ -30,7 +33,7 @@ export async function GET(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.debug(input);
|
log.info({input: input}, "Dispatch Storage");
|
||||||
|
|
||||||
const result = await dispatchStorage(input, undefined, storageId);
|
const result = await dispatchStorage(input, undefined, storageId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {auth} from "@/lib/auth/auth";
|
import {auth} from "@/lib/auth/auth";
|
||||||
import {headers} from "next/headers";
|
import {headers} from "next/headers";
|
||||||
import {db} from "@/db";
|
|
||||||
import * as drizzleDb from "@/db";
|
|
||||||
import {eq} from "drizzle-orm";
|
|
||||||
import {StorageInput} from "@/features/storages/types";
|
import {StorageInput} from "@/features/storages/types";
|
||||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
import {Readable} from "node:stream";
|
import {Readable} from "node:stream";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/files/images"});
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
req: Request,
|
req: Request,
|
||||||
@@ -56,7 +56,7 @@ export async function GET(
|
|||||||
const result = await dispatchStorage(input, undefined, storageId);
|
const result = await dispatchStorage(input, undefined, storageId);
|
||||||
|
|
||||||
if (!result.file || !(result.file instanceof Readable)) {
|
if (!result.file || !(result.file instanceof Readable)) {
|
||||||
console.error(`An error occurred while getting file :`, result);
|
log.error({error: result}, `An error occurred while getting file`);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Invalid file payload"},
|
{error: "Invalid file payload"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
@@ -82,7 +82,7 @@ export async function GET(
|
|||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error streaming image:", err);
|
log.error({error: err}, `Error streaming image`);
|
||||||
return NextResponse.json({error: "Error fetching file"}, {status: 500});
|
return NextResponse.json({error: "Error fetching file"}, {status: 500});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,9 @@ import {NextResponse} from "next/server";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import {env} from "@/env.mjs";
|
import {env} from "@/env.mjs";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "api/tus/hooks"});
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
try {
|
try {
|
||||||
@@ -13,7 +15,7 @@ export async function POST(request: Request) {
|
|||||||
const uploadOffset = headers["Upload-Offset"]?.[0];
|
const uploadOffset = headers["Upload-Offset"]?.[0];
|
||||||
const status = headers["X-Status"]?.[0];
|
const status = headers["X-Status"]?.[0];
|
||||||
|
|
||||||
console.log(`Upload ID : ${event.Upload.ID} (${uploadOffset}/${uploadLength})`);
|
log.info(`Upload ID : ${event.Upload.ID} (${uploadOffset}/${uploadLength})`);
|
||||||
|
|
||||||
if (status === "success") {
|
if (status === "success") {
|
||||||
if (
|
if (
|
||||||
@@ -29,9 +31,7 @@ export async function POST(request: Request) {
|
|||||||
return NextResponse.json({error: "Missing X-File-Path"}, {status: 500});
|
return NextResponse.json({error: "Missing X-File-Path"}, {status: 500});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uploadDir = path.join(env.PRIVATE_PATH!, "/uploads/");
|
||||||
// const uploadDir = path.join(process.cwd(), "/private/uploads/");
|
|
||||||
const uploadDir = path.join(env.PRIVATE_PATH, "/uploads/");
|
|
||||||
|
|
||||||
const oldFilePath = path.join(uploadDir, "tmp", id);
|
const oldFilePath = path.join(uploadDir, "tmp", id);
|
||||||
const newFilePath = path.join(uploadDir, filePath);
|
const newFilePath = path.join(uploadDir, filePath);
|
||||||
@@ -74,7 +74,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
return NextResponse.json({});
|
return NextResponse.json({});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Hook error:", error);
|
log.error({error: error},"TUS Hook error");
|
||||||
return NextResponse.json({error: "Internal server error"}, {status: 500});
|
return NextResponse.json({error: "Internal server error"}, {status: 500});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "portabase",
|
"name": "portabase",
|
||||||
"version": "1.9.2",
|
"version": "1.9.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack -p 8887",
|
"dev": "next dev --turbopack -p 8887",
|
||||||
@@ -78,6 +78,8 @@
|
|||||||
"nodemailer": "^7.0.13",
|
"nodemailer": "^7.0.13",
|
||||||
"npm-check-updates": "^18.3.1",
|
"npm-check-updates": "^18.3.1",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.20.0",
|
||||||
|
"pino": "^10.3.1",
|
||||||
|
"pino-pretty": "^13.1.3",
|
||||||
"prettier": "^3.8.1",
|
"prettier": "^3.8.1",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-day-picker": "9.7.0",
|
"react-day-picker": "9.7.0",
|
||||||
|
|||||||
Generated
+152
@@ -197,6 +197,12 @@ importers:
|
|||||||
pg:
|
pg:
|
||||||
specifier: ^8.20.0
|
specifier: ^8.20.0
|
||||||
version: 8.20.0
|
version: 8.20.0
|
||||||
|
pino:
|
||||||
|
specifier: ^10.3.1
|
||||||
|
version: 10.3.1
|
||||||
|
pino-pretty:
|
||||||
|
specifier: ^13.1.3
|
||||||
|
version: 13.1.3
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.8.1
|
specifier: ^3.8.1
|
||||||
version: 3.8.1
|
version: 3.8.1
|
||||||
@@ -2010,6 +2016,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oeQJs1aa8Ghke8JIK9yuq/+KjMiaYeDZ38jx7MhkXncXlUKjqQ3wEm2X3qCKyjo+ZZofZj+WsEEiqkTtRuE2xQ==}
|
resolution: {integrity: sha512-oeQJs1aa8Ghke8JIK9yuq/+KjMiaYeDZ38jx7MhkXncXlUKjqQ3wEm2X3qCKyjo+ZZofZj+WsEEiqkTtRuE2xQ==}
|
||||||
engines: {node: ^20.9.0 || >=22.0.0, npm: '>=10.8.2'}
|
engines: {node: ^20.9.0 || >=22.0.0, npm: '>=10.8.2'}
|
||||||
|
|
||||||
|
'@pinojs/redact@0.4.0':
|
||||||
|
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
|
||||||
|
|
||||||
'@playwright/test@1.58.2':
|
'@playwright/test@1.58.2':
|
||||||
resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
|
resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3722,6 +3731,10 @@ packages:
|
|||||||
async@3.2.6:
|
async@3.2.6:
|
||||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||||
|
|
||||||
|
atomic-sleep@1.0.0:
|
||||||
|
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
attr-accept@2.2.5:
|
attr-accept@2.2.5:
|
||||||
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
|
resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -4077,6 +4090,9 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
colorette@2.0.20:
|
||||||
|
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
|
||||||
|
|
||||||
colors@1.4.0:
|
colors@1.4.0:
|
||||||
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
@@ -4266,6 +4282,9 @@ packages:
|
|||||||
date-fns@4.1.0:
|
date-fns@4.1.0:
|
||||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||||
|
|
||||||
|
dateformat@4.6.3:
|
||||||
|
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
|
||||||
|
|
||||||
debounce@2.2.0:
|
debounce@2.2.0:
|
||||||
resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==}
|
resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4830,6 +4849,9 @@ packages:
|
|||||||
fast-content-type-parse@3.0.0:
|
fast-content-type-parse@3.0.0:
|
||||||
resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
|
resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
|
||||||
|
|
||||||
|
fast-copy@4.0.2:
|
||||||
|
resolution: {integrity: sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==}
|
||||||
|
|
||||||
fast-deep-equal@2.0.1:
|
fast-deep-equal@2.0.1:
|
||||||
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
|
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
|
||||||
|
|
||||||
@@ -4854,6 +4876,9 @@ packages:
|
|||||||
fast-levenshtein@2.0.6:
|
fast-levenshtein@2.0.6:
|
||||||
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||||
|
|
||||||
|
fast-safe-stringify@2.1.1:
|
||||||
|
resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
|
||||||
|
|
||||||
fast-uri@3.1.0:
|
fast-uri@3.1.0:
|
||||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||||
|
|
||||||
@@ -5143,6 +5168,9 @@ packages:
|
|||||||
header-case@2.0.4:
|
header-case@2.0.4:
|
||||||
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
|
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
|
||||||
|
|
||||||
|
help-me@5.0.0:
|
||||||
|
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
|
||||||
|
|
||||||
hermes-estree@0.25.1:
|
hermes-estree@0.25.1:
|
||||||
resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
|
resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
|
||||||
|
|
||||||
@@ -5448,6 +5476,10 @@ packages:
|
|||||||
jose@6.2.2:
|
jose@6.2.2:
|
||||||
resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==}
|
resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==}
|
||||||
|
|
||||||
|
joycon@3.1.1:
|
||||||
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
@@ -6068,6 +6100,10 @@ packages:
|
|||||||
ohash@2.0.11:
|
ohash@2.0.11:
|
||||||
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
||||||
|
|
||||||
|
on-exit-leak-free@2.1.2:
|
||||||
|
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||||
|
|
||||||
@@ -6252,6 +6288,20 @@ packages:
|
|||||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
pino-abstract-transport@3.0.0:
|
||||||
|
resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==}
|
||||||
|
|
||||||
|
pino-pretty@13.1.3:
|
||||||
|
resolution: {integrity: sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
pino-std-serializers@7.1.0:
|
||||||
|
resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==}
|
||||||
|
|
||||||
|
pino@10.3.1:
|
||||||
|
resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
pirates@4.0.7:
|
pirates@4.0.7:
|
||||||
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -6374,6 +6424,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
process-warning@5.0.0:
|
||||||
|
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
|
||||||
|
|
||||||
prompts@2.4.2:
|
prompts@2.4.2:
|
||||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -6426,6 +6479,9 @@ packages:
|
|||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
|
quick-format-unescaped@4.0.4:
|
||||||
|
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
||||||
|
|
||||||
rc9@2.1.2:
|
rc9@2.1.2:
|
||||||
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
||||||
|
|
||||||
@@ -6563,6 +6619,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
||||||
engines: {node: '>= 20.19.0'}
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
|
real-require@0.2.0:
|
||||||
|
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||||
|
engines: {node: '>= 12.13.0'}
|
||||||
|
|
||||||
recharts-scale@0.4.5:
|
recharts-scale@0.4.5:
|
||||||
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
|
||||||
|
|
||||||
@@ -6668,6 +6728,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0:
|
||||||
|
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
safer-buffer@2.1.2:
|
safer-buffer@2.1.2:
|
||||||
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
|
||||||
|
|
||||||
@@ -6688,6 +6752,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==}
|
resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
|
|
||||||
|
secure-json-parse@4.1.0:
|
||||||
|
resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==}
|
||||||
|
|
||||||
selderee@0.11.0:
|
selderee@0.11.0:
|
||||||
resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
|
resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
|
||||||
|
|
||||||
@@ -6802,6 +6869,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
|
resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
|
||||||
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
|
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
|
||||||
|
|
||||||
|
sonic-boom@4.2.1:
|
||||||
|
resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==}
|
||||||
|
|
||||||
sonner@2.0.3:
|
sonner@2.0.3:
|
||||||
resolution: {integrity: sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==}
|
resolution: {integrity: sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -6942,6 +7012,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
strip-json-comments@5.0.3:
|
||||||
|
resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
strnum@2.2.2:
|
strnum@2.2.2:
|
||||||
resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==}
|
resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==}
|
||||||
|
|
||||||
@@ -7044,6 +7118,10 @@ packages:
|
|||||||
thenify@3.3.1:
|
thenify@3.3.1:
|
||||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||||
|
|
||||||
|
thread-stream@4.0.0:
|
||||||
|
resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
through2@4.0.2:
|
through2@4.0.2:
|
||||||
resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
|
resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
|
||||||
|
|
||||||
@@ -8869,6 +8947,8 @@ snapshots:
|
|||||||
|
|
||||||
'@phun-ky/typeof@2.0.3': {}
|
'@phun-ky/typeof@2.0.3': {}
|
||||||
|
|
||||||
|
'@pinojs/redact@0.4.0': {}
|
||||||
|
|
||||||
'@playwright/test@1.58.2':
|
'@playwright/test@1.58.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
playwright: 1.58.2
|
playwright: 1.58.2
|
||||||
@@ -11206,6 +11286,8 @@ snapshots:
|
|||||||
|
|
||||||
async@3.2.6: {}
|
async@3.2.6: {}
|
||||||
|
|
||||||
|
atomic-sleep@1.0.0: {}
|
||||||
|
|
||||||
attr-accept@2.2.5: {}
|
attr-accept@2.2.5: {}
|
||||||
|
|
||||||
autoprefixer@10.4.21(postcss@8.5.8):
|
autoprefixer@10.4.21(postcss@8.5.8):
|
||||||
@@ -11578,6 +11660,8 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
colorette@2.0.20: {}
|
||||||
|
|
||||||
colors@1.4.0: {}
|
colors@1.4.0: {}
|
||||||
|
|
||||||
commander@13.1.0: {}
|
commander@13.1.0: {}
|
||||||
@@ -11770,6 +11854,8 @@ snapshots:
|
|||||||
|
|
||||||
date-fns@4.1.0: {}
|
date-fns@4.1.0: {}
|
||||||
|
|
||||||
|
dateformat@4.6.3: {}
|
||||||
|
|
||||||
debounce@2.2.0: {}
|
debounce@2.2.0: {}
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
@@ -12507,6 +12593,8 @@ snapshots:
|
|||||||
|
|
||||||
fast-content-type-parse@3.0.0: {}
|
fast-content-type-parse@3.0.0: {}
|
||||||
|
|
||||||
|
fast-copy@4.0.2: {}
|
||||||
|
|
||||||
fast-deep-equal@2.0.1: {}
|
fast-deep-equal@2.0.1: {}
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
@@ -12533,6 +12621,8 @@ snapshots:
|
|||||||
|
|
||||||
fast-levenshtein@2.0.6: {}
|
fast-levenshtein@2.0.6: {}
|
||||||
|
|
||||||
|
fast-safe-stringify@2.1.1: {}
|
||||||
|
|
||||||
fast-uri@3.1.0: {}
|
fast-uri@3.1.0: {}
|
||||||
|
|
||||||
fast-xml-builder@1.1.4:
|
fast-xml-builder@1.1.4:
|
||||||
@@ -12838,6 +12928,8 @@ snapshots:
|
|||||||
capital-case: 1.0.4
|
capital-case: 1.0.4
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
help-me@5.0.0: {}
|
||||||
|
|
||||||
hermes-estree@0.25.1: {}
|
hermes-estree@0.25.1: {}
|
||||||
|
|
||||||
hermes-parser@0.25.1:
|
hermes-parser@0.25.1:
|
||||||
@@ -13138,6 +13230,8 @@ snapshots:
|
|||||||
|
|
||||||
jose@6.2.2: {}
|
jose@6.2.2: {}
|
||||||
|
|
||||||
|
joycon@3.1.1: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
js-yaml@4.1.1:
|
js-yaml@4.1.1:
|
||||||
@@ -13676,6 +13770,8 @@ snapshots:
|
|||||||
|
|
||||||
ohash@2.0.11: {}
|
ohash@2.0.11: {}
|
||||||
|
|
||||||
|
on-exit-leak-free@2.1.2: {}
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
@@ -13899,6 +13995,42 @@ snapshots:
|
|||||||
|
|
||||||
pify@2.3.0: {}
|
pify@2.3.0: {}
|
||||||
|
|
||||||
|
pino-abstract-transport@3.0.0:
|
||||||
|
dependencies:
|
||||||
|
split2: 4.2.0
|
||||||
|
|
||||||
|
pino-pretty@13.1.3:
|
||||||
|
dependencies:
|
||||||
|
colorette: 2.0.20
|
||||||
|
dateformat: 4.6.3
|
||||||
|
fast-copy: 4.0.2
|
||||||
|
fast-safe-stringify: 2.1.1
|
||||||
|
help-me: 5.0.0
|
||||||
|
joycon: 3.1.1
|
||||||
|
minimist: 1.2.8
|
||||||
|
on-exit-leak-free: 2.1.2
|
||||||
|
pino-abstract-transport: 3.0.0
|
||||||
|
pump: 3.0.4
|
||||||
|
secure-json-parse: 4.1.0
|
||||||
|
sonic-boom: 4.2.1
|
||||||
|
strip-json-comments: 5.0.3
|
||||||
|
|
||||||
|
pino-std-serializers@7.1.0: {}
|
||||||
|
|
||||||
|
pino@10.3.1:
|
||||||
|
dependencies:
|
||||||
|
'@pinojs/redact': 0.4.0
|
||||||
|
atomic-sleep: 1.0.0
|
||||||
|
on-exit-leak-free: 2.1.2
|
||||||
|
pino-abstract-transport: 3.0.0
|
||||||
|
pino-std-serializers: 7.1.0
|
||||||
|
process-warning: 5.0.0
|
||||||
|
quick-format-unescaped: 4.0.4
|
||||||
|
real-require: 0.2.0
|
||||||
|
safe-stable-stringify: 2.5.0
|
||||||
|
sonic-boom: 4.2.1
|
||||||
|
thread-stream: 4.0.0
|
||||||
|
|
||||||
pirates@4.0.7: {}
|
pirates@4.0.7: {}
|
||||||
|
|
||||||
pkg-types@2.3.0:
|
pkg-types@2.3.0:
|
||||||
@@ -14003,6 +14135,8 @@ snapshots:
|
|||||||
|
|
||||||
prismjs@1.30.0: {}
|
prismjs@1.30.0: {}
|
||||||
|
|
||||||
|
process-warning@5.0.0: {}
|
||||||
|
|
||||||
prompts@2.4.2:
|
prompts@2.4.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
kleur: 3.0.3
|
kleur: 3.0.3
|
||||||
@@ -14076,6 +14210,8 @@ snapshots:
|
|||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
|
quick-format-unescaped@4.0.4: {}
|
||||||
|
|
||||||
rc9@2.1.2:
|
rc9@2.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
@@ -14258,6 +14394,8 @@ snapshots:
|
|||||||
|
|
||||||
readdirp@5.0.0: {}
|
readdirp@5.0.0: {}
|
||||||
|
|
||||||
|
real-require@0.2.0: {}
|
||||||
|
|
||||||
recharts-scale@0.4.5:
|
recharts-scale@0.4.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
decimal.js-light: 2.5.1
|
decimal.js-light: 2.5.1
|
||||||
@@ -14403,6 +14541,8 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-regex: 1.2.1
|
is-regex: 1.2.1
|
||||||
|
|
||||||
|
safe-stable-stringify@2.5.0: {}
|
||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
samlify@2.11.0:
|
samlify@2.11.0:
|
||||||
@@ -14429,6 +14569,8 @@ snapshots:
|
|||||||
ajv-formats: 2.1.1(ajv@8.18.0)
|
ajv-formats: 2.1.1(ajv@8.18.0)
|
||||||
ajv-keywords: 5.1.0(ajv@8.18.0)
|
ajv-keywords: 5.1.0(ajv@8.18.0)
|
||||||
|
|
||||||
|
secure-json-parse@4.1.0: {}
|
||||||
|
|
||||||
selderee@0.11.0:
|
selderee@0.11.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
parseley: 0.12.1
|
parseley: 0.12.1
|
||||||
@@ -14643,6 +14785,10 @@ snapshots:
|
|||||||
ip-address: 10.1.0
|
ip-address: 10.1.0
|
||||||
smart-buffer: 4.2.0
|
smart-buffer: 4.2.0
|
||||||
|
|
||||||
|
sonic-boom@4.2.1:
|
||||||
|
dependencies:
|
||||||
|
atomic-sleep: 1.0.0
|
||||||
|
|
||||||
sonner@2.0.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
sonner@2.0.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
@@ -14800,6 +14946,8 @@ snapshots:
|
|||||||
|
|
||||||
strip-json-comments@3.1.1: {}
|
strip-json-comments@3.1.1: {}
|
||||||
|
|
||||||
|
strip-json-comments@5.0.3: {}
|
||||||
|
|
||||||
strnum@2.2.2: {}
|
strnum@2.2.2: {}
|
||||||
|
|
||||||
styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.0.0):
|
styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.0.0):
|
||||||
@@ -14927,6 +15075,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
any-promise: 1.3.0
|
any-promise: 1.3.0
|
||||||
|
|
||||||
|
thread-stream@4.0.0:
|
||||||
|
dependencies:
|
||||||
|
real-require: 0.2.0
|
||||||
|
|
||||||
through2@4.0.2:
|
through2@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export function SocialAuthButtons({ providers }: { providers: AuthProviderConfig
|
|||||||
providerType: "oidc",
|
providerType: "oidc",
|
||||||
callbackURL: "/dashboard",
|
callbackURL: "/dashboard",
|
||||||
});
|
});
|
||||||
|
console.log(result);
|
||||||
} else {
|
} else {
|
||||||
result = await authClient.signIn.social({
|
result = await authClient.signIn.social({
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|||||||
+6
-3
@@ -17,12 +17,15 @@ import * as storagePolicy from "@/db/schema/13_storage-policy";
|
|||||||
import * as backupStorage from "@/db/schema/14_storage-backup";
|
import * as backupStorage from "@/db/schema/14_storage-backup";
|
||||||
import * as healthcheckLog from "@/db/schema/15_healthcheck-log";
|
import * as healthcheckLog from "@/db/schema/15_healthcheck-log";
|
||||||
|
|
||||||
|
const log = logger.child({module: "db"});
|
||||||
|
|
||||||
|
|
||||||
import {Pool} from "pg";
|
import {Pool} from "pg";
|
||||||
|
|
||||||
// Do not delete
|
// Do not delete
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import {migrate} from "drizzle-orm/node-postgres/migrator";
|
import {migrate} from "drizzle-orm/node-postgres/migrator";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
dotenv.config({
|
dotenv.config({
|
||||||
path: ".env",
|
path: ".env",
|
||||||
@@ -66,12 +69,12 @@ export async function makeMigration() {
|
|||||||
|
|
||||||
const database = drizzle({client: pool});
|
const database = drizzle({client: pool});
|
||||||
|
|
||||||
console.log("Running migrations...");
|
log.info("Running migrations...");
|
||||||
try {
|
try {
|
||||||
await migrate(database, {migrationsFolder: "./src/db/migrations"});
|
await migrate(database, {migrationsFolder: "./src/db/migrations"});
|
||||||
console.log("Migrations applied successfully.");
|
log.info("Migrations applied successfully.");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error applying migrations:", error);
|
log.error({error: error}, "Error applying migrations:");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import * as drizzleDb from "@/db";
|
|||||||
import {and, eq, gte, isNotNull, lt} from "drizzle-orm";
|
import {and, eq, gte, isNotNull, lt} from "drizzle-orm";
|
||||||
import {dispatchNotification} from "@/features/notifications/dispatch";
|
import {dispatchNotification} from "@/features/notifications/dispatch";
|
||||||
import {EventPayload} from "@/features/notifications/types";
|
import {EventPayload} from "@/features/notifications/types";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/healthcheck"});
|
||||||
|
|
||||||
export async function getHealthLast12hLogs({id}: { id: string }) {
|
export async function getHealthLast12hLogs({id}: { id: string }) {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
@@ -19,7 +22,6 @@ export async function getHealthLast12hLogs({id}: { id: string }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function deleteHealthLogsOlderThan12h() {
|
export async function deleteHealthLogsOlderThan12h() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const threshold = new Date(now.getTime() - 12 * 60 * 60 * 1000)
|
const threshold = new Date(now.getTime() - 12 * 60 * 60 * 1000)
|
||||||
@@ -31,7 +33,7 @@ export async function deleteHealthLogsOlderThan12h() {
|
|||||||
lt(drizzleDb.schemas.healthcheckLog.date, threshold)
|
lt(drizzleDb.schemas.healthcheckLog.date, threshold)
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(`Number of logs found to delete: ${logsToDelete.length}`)
|
log.info({name: "deleteHealthLogsOlderThan12h"},`Number of logs found to delete: ${logsToDelete.length}`)
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.delete(drizzleDb.schemas.healthcheckLog)
|
.delete(drizzleDb.schemas.healthcheckLog)
|
||||||
@@ -56,7 +58,7 @@ export async function checkAgentsHealthError() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!settings.defaultNotificationChannelId) {
|
if (!settings.defaultNotificationChannelId) {
|
||||||
console.error("No default notification channel id found.");
|
log.error({name: "checkAgentsHealthError"},`No default notification channel id found.`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +91,7 @@ export async function checkAgentsHealthError() {
|
|||||||
error: "Agent is down",
|
error: "Agent is down",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
log.info({name: "checkAgentsHealthError", payload: payload},`Agent Healthcheck Notification`)
|
||||||
console.log("[Agent Healthcheck] :", payload);
|
|
||||||
|
|
||||||
await dispatchNotification(
|
await dispatchNotification(
|
||||||
payload,
|
payload,
|
||||||
@@ -156,7 +157,6 @@ export async function checkDatabasesHealthError() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const promises = policiesToUse.map(alertPolicy => {
|
const promises = policiesToUse.map(alertPolicy => {
|
||||||
|
|
||||||
const payload: EventPayload = {
|
const payload: EventPayload = {
|
||||||
@@ -171,15 +171,13 @@ export async function checkDatabasesHealthError() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("[Database Healthcheck] :", payload);
|
log.info({name: "checkDatabasesHealthError", payload: payload},`Database Healthcheck Notification`)
|
||||||
|
|
||||||
return dispatchNotification(payload, alertPolicy.id == null ? undefined : alertPolicy.id, alertPolicy.id ? undefined : alertPolicy.notificationChannelId, undefined);
|
return dispatchNotification(payload, alertPolicy.id == null ? undefined : alertPolicy.id, alertPolicy.id ? undefined : alertPolicy.notificationChannelId, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ export const env = createEnv({
|
|||||||
.regex(/^https?:\/\//, "URL must start with http:// or https://"),
|
.regex(/^https?:\/\//, "URL must start with http:// or https://"),
|
||||||
PROJECT_SECRET: z.string(),
|
PROJECT_SECRET: z.string(),
|
||||||
|
|
||||||
|
TRUSTED_DOMAINS: z.string().optional(),
|
||||||
|
|
||||||
SMTP_PASSWORD: z.string().optional(),
|
SMTP_PASSWORD: z.string().optional(),
|
||||||
SMTP_FROM: z.string().optional(),
|
SMTP_FROM: z.string().optional(),
|
||||||
SMTP_HOST: z.string().optional(),
|
SMTP_HOST: z.string().optional(),
|
||||||
@@ -101,6 +103,8 @@ export const env = createEnv({
|
|||||||
|
|
||||||
DATABASE_URL: process.env.DATABASE_URL,
|
DATABASE_URL: process.env.DATABASE_URL,
|
||||||
|
|
||||||
|
TRUSTED_DOMAINS: process.env.TRUSTED_DOMAINS,
|
||||||
|
|
||||||
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
SMTP_PASSWORD: process.env.SMTP_PASSWORD,
|
||||||
SMTP_FROM: process.env.SMTP_FROM,
|
SMTP_FROM: process.env.SMTP_FROM,
|
||||||
SMTP_HOST: process.env.SMTP_HOST,
|
SMTP_HOST: process.env.SMTP_HOST,
|
||||||
|
|||||||
+19
-1
@@ -516,9 +516,27 @@ export const auth = betterAuth({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},*/
|
},*/
|
||||||
trustedOrigins: [env.PROJECT_URL!, "http://app"],
|
// trustedOrigins: [env.PROJECT_URL!, "http://app"],
|
||||||
|
trustedOrigins: async (request) => {
|
||||||
|
const trustedOrigins = await queryTrustedDomains();
|
||||||
|
return trustedOrigins;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const queryTrustedDomains = async (): Promise<string[]> => {
|
||||||
|
const envDomains = env.TRUSTED_DOMAINS || "";
|
||||||
|
const domains = envDomains
|
||||||
|
.split(",")
|
||||||
|
.map((d) => d.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
if (env.PROJECT_URL) domains.push(env.PROJECT_URL);
|
||||||
|
domains.push("http://app")
|
||||||
|
|
||||||
|
return domains;
|
||||||
|
};
|
||||||
|
|
||||||
/*export const signUpUser = async (email: string, password: string, name: string) => {
|
/*export const signUpUser = async (email: string, password: string, name: string) => {
|
||||||
const user = await auth.api.signUpEmail({
|
const user = await auth.api.signUpEmail({
|
||||||
body: {
|
body: {
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import pino, { type Logger } from "pino";
|
||||||
|
|
||||||
|
const isProd = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
|
function getLocalTimestamp() {
|
||||||
|
const date = new Date();
|
||||||
|
|
||||||
|
const formatted = new Intl.DateTimeFormat("en-US", {
|
||||||
|
timeZone: process.env.TZ,
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit"
|
||||||
|
}).format(date).replace(" ", "T");
|
||||||
|
|
||||||
|
return `,"time":"${formatted}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const logger: Logger = pino({
|
||||||
|
level: isProd ? "info" : "debug",
|
||||||
|
base: null,
|
||||||
|
|
||||||
|
...(isProd
|
||||||
|
? {
|
||||||
|
timestamp: getLocalTimestamp,
|
||||||
|
formatters: {
|
||||||
|
level(label) {
|
||||||
|
return { level: label.toUpperCase() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
timestamp: getLocalTimestamp,
|
||||||
|
transport: {
|
||||||
|
target: "pino-pretty",
|
||||||
|
options: {
|
||||||
|
colorize: true,
|
||||||
|
translateTime: "yyyy-mm-dd HH:MM:ss",
|
||||||
|
ignore: "pid,hostname",
|
||||||
|
levelFirst: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -2,6 +2,9 @@ import {db} from "@/db";
|
|||||||
import {and, eq, isNotNull, isNull} from "drizzle-orm";
|
import {and, eq, isNotNull, isNull} from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/cleaning"});
|
||||||
|
|
||||||
export const backupCleanTask = async () => {
|
export const backupCleanTask = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -11,8 +14,7 @@ export const backupCleanTask = async () => {
|
|||||||
eq(drizzleDb.schemas.backup.status, "ongoing")
|
eq(drizzleDb.schemas.backup.status, "ongoing")
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
log.info(`Backups to clean: ${backups.length}`);
|
||||||
console.log(`Backups to clean: ${backups.length}`);
|
|
||||||
|
|
||||||
for (const backup of backups) {
|
for (const backup of backups) {
|
||||||
await db.update(drizzleDb.schemas.backup).set(withUpdatedAt({
|
await db.update(drizzleDb.schemas.backup).set(withUpdatedAt({
|
||||||
@@ -22,7 +24,7 @@ export const backupCleanTask = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Backup cleanup failed:", e);
|
log.info({name: "backupCleanTask", error: e},`Backup cleanup failed`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -5,7 +5,9 @@ import {enforceRetentionGFS} from "@/lib/tasks/database/retention-gsf";
|
|||||||
import {retentionPolicy} from "@/db/schema/07_database";
|
import {retentionPolicy} from "@/db/schema/07_database";
|
||||||
import {isNull} from "drizzle-orm";
|
import {isNull} from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/database"});
|
||||||
|
|
||||||
export const retentionCleanTask = async () => {
|
export const retentionCleanTask = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -17,13 +19,13 @@ export const retentionCleanTask = async () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(`Retention databases number: ${databases.length}`);
|
log.info(`Retention databases number: ${databases.length}`);
|
||||||
for (const db of databases) {
|
for (const db of databases) {
|
||||||
if (!db.retentionPolicy) continue;
|
if (!db.retentionPolicy) continue;
|
||||||
await enforceRetention(db.id, db.retentionPolicy);
|
await enforceRetention(db.id, db.retentionPolicy);
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Retention cleanup failed:", e);
|
log.error({error: e},"Retention cleanup failed");
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -32,7 +34,9 @@ export async function enforceRetention(
|
|||||||
databaseId: string,
|
databaseId: string,
|
||||||
policy: typeof retentionPolicy.$inferSelect
|
policy: typeof retentionPolicy.$inferSelect
|
||||||
) {
|
) {
|
||||||
console.log(`Retention started for ${databaseId}`);
|
;
|
||||||
|
log.info({name: "enforceRetention"},`Retention started for ${databaseId}`);
|
||||||
|
|
||||||
switch (policy.type) {
|
switch (policy.type) {
|
||||||
case "count":
|
case "count":
|
||||||
await enforceRetentionCount(databaseId, policy.count ?? 7);
|
await enforceRetentionCount(databaseId, policy.count ?? 7);
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import * as drizzleDb from "@/db";
|
|||||||
import {db} from "@/db";
|
import {db} from "@/db";
|
||||||
import {and, desc, eq, isNull} from "drizzle-orm";
|
import {and, desc, eq, isNull} from "drizzle-orm";
|
||||||
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
||||||
import {toast} from "sonner";
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/database/retention-count"});
|
||||||
|
|
||||||
export async function enforceRetentionCount(databaseId: string, count: number) {
|
export async function enforceRetentionCount(databaseId: string, count: number) {
|
||||||
console.log(`[Retention Count] - ${databaseId} : started`);
|
log.info({ name: "enforceRetentionCount"}, `Retention count started for databaseId: ${databaseId}`);
|
||||||
const backups = await db.query.backup.findMany({
|
const backups = await db.query.backup.findMany({
|
||||||
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseId), isNull(drizzleDb.schemas.backup.deletedAt)),
|
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseId), isNull(drizzleDb.schemas.backup.deletedAt)),
|
||||||
orderBy: desc(drizzleDb.schemas.backup.createdAt),
|
orderBy: desc(drizzleDb.schemas.backup.createdAt),
|
||||||
@@ -19,7 +21,7 @@ export async function enforceRetentionCount(databaseId: string, count: number) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const toDelete = backups.slice(count);
|
const toDelete = backups.slice(count);
|
||||||
console.log(`[Retention Count] - ${databaseId} : ${toDelete.length} backups to delete`);
|
log.info({ name: "enforceRetentionCount"}, `Found ${toDelete.length} backups to delete for databaseId: ${databaseId}`);
|
||||||
|
|
||||||
for (const b of toDelete) {
|
for (const b of toDelete) {
|
||||||
const result = await deleteBackupCronAction({
|
const result = await deleteBackupCronAction({
|
||||||
@@ -29,9 +31,9 @@ export async function enforceRetentionCount(databaseId: string, count: number) {
|
|||||||
|
|
||||||
const inner = result?.data;
|
const inner = result?.data;
|
||||||
if (inner?.success) {
|
if (inner?.success) {
|
||||||
console.log(`[Retention Count] - (databaseId:${b.databaseId}) - (backupId: ${b.id}) : successfully deleted`);
|
log.info({ name: "enforceRetentionCount"}, `(databaseId:${b.databaseId}) - (backupId: ${b.id}) : successfully deleted`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`[Retention Count] - (databaseId:${b.databaseId}) - (backupId: ${b.id}) : an error occurred - ${inner?.actionError?.message}`);
|
log.info({ name: "enforceRetentionCount"}, `(databaseId:${b.databaseId}) - (backupId: ${b.id}) : an error occurred - ${inner?.actionError?.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,13 @@ import {db} from "@/db";
|
|||||||
import {eq, lt, and, desc, isNull} from "drizzle-orm";
|
import {eq, lt, and, desc, isNull} from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/database/retention-days"});
|
||||||
|
|
||||||
export async function enforceRetentionDays(databaseId: string, days: number) {
|
export async function enforceRetentionDays(databaseId: string, days: number) {
|
||||||
console.log(`Enforce Retention Days starting for ${databaseId}`);
|
log.info({ name: "enforceRetentionDays"}, `Enforce Retention Days starting for ${databaseId}`);
|
||||||
|
|
||||||
const cutoff = new Date(Date.now() - days * 86400000);
|
const cutoff = new Date(Date.now() - days * 86400000);
|
||||||
|
|
||||||
const expiredBackups = await db.query.backup.findMany({
|
const expiredBackups = await db.query.backup.findMany({
|
||||||
@@ -31,9 +35,9 @@ export async function enforceRetentionDays(databaseId: string, days: number) {
|
|||||||
|
|
||||||
const inner = result?.data;
|
const inner = result?.data;
|
||||||
if (inner?.success) {
|
if (inner?.success) {
|
||||||
console.log(`[Retention Days] - (databaseId:${backup.databaseId}) - (backupId: ${backup.id}) : successfully deleted`);
|
log.info({ name: "enforceRetentionDays"}, `(databaseId:${backup.databaseId}) - (backupId: ${backup.id}) : successfully deleted`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`[Retention Days] - (databaseId:${backup.databaseId}) - (backupId: ${backup.id}) : an error occurred - ${inner?.actionError?.message}`);
|
log.info({ name: "enforceRetentionDays"}, `(databaseId:${backup.databaseId}) - (backupId: ${backup.id}) : an error occurred - ${inner?.actionError?.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import {subDays, subWeeks, subMonths, subYears, startOfWeek, startOfMonth, start
|
|||||||
import {eq, desc, isNull, and} from "drizzle-orm";
|
import {eq, desc, isNull, and} from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
import {deleteBackupCronAction} from "@/lib/tasks/database/utils/delete";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks/database/retention-gsf"});
|
||||||
|
|
||||||
export async function enforceRetentionGFS(databaseId: string, gfsSettings: {
|
export async function enforceRetentionGFS(databaseId: string, gfsSettings: {
|
||||||
daily: number;
|
daily: number;
|
||||||
@@ -10,7 +13,7 @@ export async function enforceRetentionGFS(databaseId: string, gfsSettings: {
|
|||||||
monthly: number;
|
monthly: number;
|
||||||
yearly: number;
|
yearly: number;
|
||||||
}) {
|
}) {
|
||||||
console.log(`Enforce Retention GFS starting for ${databaseId}`);
|
log.info({ name: "enforceRetentionGFS"}, `Retention GFS started for databaseId: ${databaseId}`);
|
||||||
|
|
||||||
const backups = await db.query.backup.findMany({
|
const backups = await db.query.backup.findMany({
|
||||||
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseId), isNull(drizzleDb.schemas.backup.deletedAt)),
|
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseId), isNull(drizzleDb.schemas.backup.deletedAt)),
|
||||||
@@ -69,9 +72,9 @@ export async function enforceRetentionGFS(databaseId: string, gfsSettings: {
|
|||||||
|
|
||||||
const inner = result?.data;
|
const inner = result?.data;
|
||||||
if (inner?.success) {
|
if (inner?.success) {
|
||||||
console.log(`[Retention GFS] - (databaseId:${b.databaseId}) - (backupId: ${b.id}) : successfully deleted`);
|
log.info({ name: "enforceRetentionGFS"}, `(databaseId:${b.databaseId}) - (backupId: ${b.id}) : successfully deleted`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`[Retention GFS] - (databaseId:${b.databaseId}) - (backupId: ${b.id}) : an error occurred - ${inner?.actionError?.message}`);
|
log.info({ name: "enforceRetentionGFS"}, `(databaseId:${b.databaseId}) - (backupId: ${b.id}) : an error occurred - ${inner?.actionError?.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-8
@@ -7,41 +7,44 @@ import {
|
|||||||
checkDatabasesHealthError,
|
checkDatabasesHealthError,
|
||||||
deleteHealthLogsOlderThan12h
|
deleteHealthLogsOlderThan12h
|
||||||
} from "@/db/services/healthcheck";
|
} from "@/db/services/healthcheck";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "tasks"});
|
||||||
|
|
||||||
export const retentionJob = cron.schedule(env.RETENTION_CRON, async () => {
|
export const retentionJob = cron.schedule(env.RETENTION_CRON, async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Retention Job : Starting task");
|
log.info({ job: "cron", action: "start", name: "retentionJob" }, "Retention Job started");
|
||||||
await retentionCleanTask();
|
await retentionCleanTask();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[CRON] Error:`, err);
|
log.error({ job: "cron", name: "retentionJob", error: err }, "Retention Job Error");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const cleaningJob = cron.schedule("* * * * *", async () => {
|
export const cleaningJob = cron.schedule("* * * * *", async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Cleaning Job : Starting task");
|
log.info({ job: "cron", action: "start", name: "cleaningJob" }, "Cleaning Job started");
|
||||||
await backupCleanTask();
|
await backupCleanTask();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[CRON] Error:`, err);
|
log.error({ job: "cron", name: "cleaningJob", error: err }, "Cleaning Job Error");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const cleaningHealthcheckLogsJob = cron.schedule(env.CLEANING_HEALTHCHECK_LOGS_CRON, async () => {
|
export const cleaningHealthcheckLogsJob = cron.schedule(env.CLEANING_HEALTHCHECK_LOGS_CRON, async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Cleaning Healthcheck Logs Job : Starting task");
|
log.info({ job: "cron", action: "start", name: "cleaningHealthcheckLogsJob" }, "Cleaning Health Logs Job started");
|
||||||
await deleteHealthLogsOlderThan12h();
|
await deleteHealthLogsOlderThan12h();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[CRON] Error:`, err);
|
log.error({ job: "cron", name: "cleaningHealthcheckLogsJob", error: err }, "Cleaning Health Logs Job Error");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export const healthcheckAgentAndDatabaseJob = cron.schedule(env.HEALTHCHECK_CRON, async () => {
|
export const healthcheckAgentAndDatabaseJob = cron.schedule(env.HEALTHCHECK_CRON, async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Healthcheck Job : Starting task");
|
log.info({ job: "cron", action: "start", name: "healthcheckAgentAndDatabaseJob" }, "Healthcheck Jobs started");
|
||||||
await checkAgentsHealthError();
|
await checkAgentsHealthError();
|
||||||
await checkDatabasesHealthError()
|
await checkDatabasesHealthError()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[CRON] Error:`, err);
|
log.error({ job: "cron", name: "healthcheckAgentAndDatabaseJob", error: err }, "Healthcheck Jobs Error");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
+17
-24
@@ -5,52 +5,45 @@ import * as drizzleDb from "@/db";
|
|||||||
import {cleaningHealthcheckLogsJob, cleaningJob, healthcheckAgentAndDatabaseJob, retentionJob} from "@/lib/tasks";
|
import {cleaningHealthcheckLogsJob, cleaningJob, healthcheckAgentAndDatabaseJob, retentionJob} from "@/lib/tasks";
|
||||||
import { generateRSAKeys, getOrCreateMasterKey } from "@/utils/rsa-keys";
|
import { generateRSAKeys, getOrCreateMasterKey } from "@/utils/rsa-keys";
|
||||||
import { StorageProviderKind } from "@/features/storages/types";
|
import { StorageProviderKind } from "@/features/storages/types";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "init"});
|
||||||
|
|
||||||
export async function init() {
|
export async function init() {
|
||||||
consoleAscii();
|
consoleAscii();
|
||||||
console.log("====Init Functions====");
|
|
||||||
|
log.info("====Init Functions====");
|
||||||
await getOrCreateMasterKey();
|
await getOrCreateMasterKey();
|
||||||
await generateRSAKeys();
|
await generateRSAKeys();
|
||||||
await makeMigration();
|
await makeMigration();
|
||||||
await createDefaultOrganization();
|
await createDefaultOrganization();
|
||||||
await createSettingsIfNotExist();
|
await createSettingsIfNotExist();
|
||||||
console.log("====Initialization completed====");
|
log.info("====Initialization completed====");
|
||||||
await setupCronJobs();
|
await setupCronJobs();
|
||||||
await setupCleaningJobs();
|
|
||||||
await setupCleaningHealthLogsJobs();
|
|
||||||
await setupHealthCheckJobs();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) ||
|
(env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) ||
|
||||||
(env.AUTH_GITHUB_ID && env.AUTH_GITHUB_SECRET)
|
(env.AUTH_GITHUB_ID && env.AUTH_GITHUB_SECRET)
|
||||||
) {
|
) {
|
||||||
console.warn(
|
log.warn(
|
||||||
"[Deprecation Warning] You have set up OAuth credentials in your environment variables, but the format is now different. Please update your environment variables to use the new format. For example, if you were using AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET, you should now use AUTH_SOCIAL_GOOGLE_CLIENT and AUTH_SOCIAL_GOOGLE_SECRET. Please refer to the documentation for more details. (https://portabase.io/docs/dashboard/auth/oauth2/setup#dynamic-providers)",
|
{
|
||||||
|
deprecated: true,
|
||||||
|
provider: "oauth_env",
|
||||||
|
message: "You have set up OAuth credentials in your environment variables, but the format is now different. Please update your environment variables to use the new format. For example, if you were using AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET, you should now use AUTH_SOCIAL_GOOGLE_CLIENT and AUTH_SOCIAL_GOOGLE_SECRET. Please refer to the documentation for more details. (https://portabase.io/docs/dashboard/auth/oauth2/setup#dynamic-providers)"
|
||||||
|
},
|
||||||
|
"Deprecated OAuth environment variables detected",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupCronJobs() {
|
async function setupCronJobs() {
|
||||||
console.log("==== Setting up Cron Jobs ====");
|
|
||||||
|
log.info("==== Setting up Cron Jobs ====");
|
||||||
retentionJob.start();
|
retentionJob.start();
|
||||||
console.log("==== Cron job started ====");
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setupCleaningJobs() {
|
|
||||||
console.log("==== Setting up Cleaning Jobs ====");
|
|
||||||
cleaningJob.start();
|
cleaningJob.start();
|
||||||
console.log("==== Cleaning job started ====");
|
|
||||||
}
|
|
||||||
|
|
||||||
async function setupCleaningHealthLogsJobs() {
|
|
||||||
console.log("==== Setting up Cleaning Healthcheck Logs Jobs ====");
|
|
||||||
cleaningHealthcheckLogsJob.start();
|
cleaningHealthcheckLogsJob.start();
|
||||||
console.log("==== Cleaning Healthcheck Logs job started ====");
|
|
||||||
}
|
|
||||||
async function setupHealthCheckJobs() {
|
|
||||||
console.log("==== Setting up Healthcheck Jobs ====");
|
|
||||||
healthcheckAgentAndDatabaseJob.start();
|
healthcheckAgentAndDatabaseJob.start();
|
||||||
console.log("==== Cleaning Healthcheck job started ====");
|
log.info("==== Cron jobs started ====");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createSettingsIfNotExist() {
|
async function createSettingsIfNotExist() {
|
||||||
@@ -129,7 +122,7 @@ async function createDefaultOrganization() {
|
|||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
console.log("==== Creating default Organization... ====");
|
log.info("==== Creating default Organization... ====");
|
||||||
await db
|
await db
|
||||||
.insert(drizzleDb.schemas.organization)
|
.insert(drizzleDb.schemas.organization)
|
||||||
.values(defaultOrganizationConf);
|
.values(defaultOrganizationConf);
|
||||||
|
|||||||
+11
-6
@@ -4,6 +4,11 @@ import {generateKeyPair} from 'crypto';
|
|||||||
import {promisify} from 'util';
|
import {promisify} from 'util';
|
||||||
import {randomBytes} from 'crypto';
|
import {randomBytes} from 'crypto';
|
||||||
import {env} from "@/env.mjs";
|
import {env} from "@/env.mjs";
|
||||||
|
import {logger} from "@/lib/logger";
|
||||||
|
|
||||||
|
const log = logger.child({module: "rsa-keys"});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const generateKeyPairAsync = promisify(generateKeyPair);
|
const generateKeyPairAsync = promisify(generateKeyPair);
|
||||||
|
|
||||||
@@ -14,17 +19,16 @@ const generateKeyPairAsync = promisify(generateKeyPair);
|
|||||||
* @param {string} [dir] path to directory
|
* @param {string} [dir] path to directory
|
||||||
* @returns {Promise<{privateKeyPath:string, publicKeyPath:string}>}
|
* @returns {Promise<{privateKeyPath:string, publicKeyPath:string}>}
|
||||||
*/
|
*/
|
||||||
export async function generateRSAKeys(dir = path.join(env.PRIVATE_PATH, '/keys')) {
|
export async function generateRSAKeys(dir = path.join(env.PRIVATE_PATH!, '/keys')) {
|
||||||
await fs.mkdir(dir, {recursive: true});
|
await fs.mkdir(dir, {recursive: true});
|
||||||
|
|
||||||
|
|
||||||
const privateKeyPath = path.join(dir, 'server_private.pem');
|
const privateKeyPath = path.join(dir, 'server_private.pem');
|
||||||
const publicKeyPath = path.join(dir, 'server_public.pem');
|
const publicKeyPath = path.join(dir, 'server_public.pem');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.access(privateKeyPath);
|
await fs.access(privateKeyPath);
|
||||||
await fs.access(publicKeyPath);
|
await fs.access(publicKeyPath);
|
||||||
console.log('RSA keys already exist. Skipping generation.');
|
log.info('RSA keys already exist. Skipping generation.');
|
||||||
return {privateKeyPath, publicKeyPath};
|
return {privateKeyPath, publicKeyPath};
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
@@ -49,13 +53,13 @@ export async function generateRSAKeys(dir = path.join(env.PRIVATE_PATH, '/keys')
|
|||||||
* @param {string} [filePath] Path to store the key
|
* @param {string} [filePath] Path to store the key
|
||||||
* @returns {Promise<Buffer>} The master key
|
* @returns {Promise<Buffer>} The master key
|
||||||
*/
|
*/
|
||||||
export async function getOrCreateMasterKey(filePath = path.join(env.PRIVATE_PATH, '/keys', 'master_key.bin')) {
|
export async function getOrCreateMasterKey(filePath = path.join(env.PRIVATE_PATH!, '/keys', 'master_key.bin')) {
|
||||||
|
|
||||||
await fs.mkdir(path.dirname(filePath), {recursive: true});
|
await fs.mkdir(path.dirname(filePath), {recursive: true});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const existing = await fs.readFile(filePath);
|
const existing = await fs.readFile(filePath);
|
||||||
console.log('Master key already exists. Skipping generation.');
|
log.info('Master key already exists. Skipping generation.');
|
||||||
return existing;
|
return existing;
|
||||||
} catch {
|
} catch {
|
||||||
// File does not exist, generate
|
// File does not exist, generate
|
||||||
@@ -64,7 +68,8 @@ export async function getOrCreateMasterKey(filePath = path.join(env.PRIVATE_PATH
|
|||||||
const key = randomBytes(32); // 256-bit key
|
const key = randomBytes(32); // 256-bit key
|
||||||
|
|
||||||
await fs.writeFile(filePath, key, {mode: 0o600});
|
await fs.writeFile(filePath, key, {mode: 0o600});
|
||||||
console.log(`Master key generated at ${filePath}`);
|
log.info("Master key already exists. Skipping generation.");
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user