Compare commits

..
13 Commits
Author SHA1 Message Date
github-actions[bot] 78ba42239d chore: release 1.10.0 2026-03-31 13:09:08 +00:00
Charles GTEandGitHub 8ffb672e26 feat: add firebird (#242) 2026-03-31 15:08:31 +02:00
Théo LAGACHEandGitHub 83ddc934ba fix: readme [skip-release] (#241)
* Update translations

* Add: firebird
2026-03-30 15:52:21 +02:00
github-actions[bot] 31cbd52703 chore: release 1.9.5 2026-03-29 12:11:43 +00:00
dd85f7a25d fix: trusted url missing, better auth crash due to update (#240)
* fix: release.yml

* fix: S3ChannelConfigSchema type port mismatch

* chore: package.json

* fix: refactoring logs and adding pino logger for production and dev.

* fix: trusted url error due to better auth update.

---------

Co-authored-by: charlesgauthereau <charles.gauthereau@soluce-technologies.com>
Co-authored-by: killianlarcher <killian.larcher@soluce-technologies.com>
2026-03-29 14:10:58 +02:00
github-actions[bot] 203c25aabe chore: release 1.9.4 2026-03-29 09:43:29 +00:00
41b1c89283 fix: logs (#238)
* fix: release.yml

* fix: S3ChannelConfigSchema type port mismatch

* chore: package.json

* fix: refactoring logs and adding pino logger for production and dev.

---------

Co-authored-by: charlesgauthereau <charles.gauthereau@soluce-technologies.com>
Co-authored-by: killianlarcher <killian.larcher@soluce-technologies.com>
2026-03-29 11:42:48 +02:00
github-actions[bot] 180ea21041 chore: release 1.9.3 2026-03-29 09:23:24 +00:00
Charles GTEandGitHub e1c0fc6917 fix: refactoring logs and adding pino logger for production and dev. (#236) 2026-03-29 11:22:28 +02:00
github-actions[bot] 057c192314 chore: release 1.9.2 2026-03-29 07:25:20 +00:00
Charles GTEandGitHub aff782aa28 fix: mariadb and mysql separation (#234) 2026-03-29 09:24:31 +02:00
github-actions[bot] 2e729cb79c chore: release 1.9.1 2026-03-28 18:01:28 +00:00
Charles GTEandGitHub d8677d74a7 fix: default notification (#233) 2026-03-28 19:00:50 +01:00
39 changed files with 5610 additions and 222 deletions
+3
View File
@@ -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
View File
@@ -31,5 +31,5 @@ keywords:
- web-ui - web-ui
- agent - agent
license: Apache-2.0 license: Apache-2.0
version: 1.9.0 version: 1.10.0
date-released: '2026-03-02' date-released: '2026-03-02'
+5 -4
View File
@@ -64,14 +64,15 @@ You have 4 ways to install Portabase:
| Engine | Support | Supported Versions | Restore | | Engine | Support | Supported Versions | Restore |
|:-------------------|:----------|:----------------------------------|:--------| |:-------------------|:----------|:----------------------------------|:--------|
| **PostgreSQL** | ✅ Stable | 12, 13, 14, 15, 16, 17 et 18 | Yes | | **PostgreSQL** | ✅ Stable | 12, 13, 14, 15, 16, 17 and 18 | Yes |
| **MySQL** | ✅ Stable | 5.7, 8 et 9 | Yes | | **MySQL** | ✅ Stable | 5.7, 8 and 9 | Yes |
| **MariaDB** | ✅ Stable | 10 et 11 | Yes | | **MariaDB** | ✅ Stable | 10 and 11 | Yes |
| **MongoDB** | ✅ Stable | 4, 5, 6, 7 et 8 | Yes | | **MongoDB** | ✅ Stable | 4, 5, 6, 7 and 8 | Yes |
| **SQLite** | ✅ Stable | 3.x | Yes | | **SQLite** | ✅ Stable | 3.x | Yes |
| **Redis** | ✅ Stable | 2.8+ | No | | **Redis** | ✅ Stable | 2.8+ | No |
| **Valkey** | ✅ Stable | 7.2+ | No | | **Valkey** | ✅ Stable | 7.2+ | No |
| **MSSQL Server** | ❌ Ongoing | - | Yes | | **MSSQL Server** | ❌ Ongoing | - | Yes |
| **Firebird** | ❌ Ongoing | - | Yes |
See the [Database Servers documentation](https://portabase.io/docs/agent/db) for version-specific backup and restore details. See the [Database Servers documentation](https://portabase.io/docs/agent/db) for version-specific backup and restore details.
+14 -12
View File
@@ -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}
); );
} }
+6 -6
View File
@@ -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 -3
View File
@@ -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}
+8 -5
View File
@@ -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));
@@ -97,6 +99,7 @@ export async function handleDatabases(body: Body, agent: Agent, lastContact: Dat
.set(withUpdatedAt({ .set(withUpdatedAt({
name: db.name, name: db.name,
agentId: agent.id, agentId: agent.id,
dbms: db.dbms as EDbmsSchema,
lastContact: db.pingStatus ? lastContact : existingDatabase.lastContact, lastContact: db.pingStatus ? lastContact : existingDatabase.lastContact,
healthErrorCount: db.pingStatus ? null : existingDatabase.healthErrorCount, healthErrorCount: db.pingStatus ? null : existingDatabase.healthErrorCount,
})) }))
@@ -184,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"})
+8 -7
View File
@@ -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}
+6 -3
View File
@@ -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);
}); });
+4 -1
View File
@@ -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);
+5 -5
View File
@@ -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});
} }
} }
+5 -5
View File
@@ -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});
} }
} }
+4 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "portabase", "name": "portabase",
"version": "1.9.0", "version": "1.10.0",
"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",
@@ -117,7 +119,7 @@
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@zenstackhq/openapi": "^2.22.1", "@zenstackhq/openapi": "^2.22.1",
"@zenstackhq/tanstack-query": "^2.22.2", "@zenstackhq/tanstack-query": "^2.22.2",
"baseline-browser-mapping": "^2.10.11", "baseline-browser-mapping": "^2.10.12",
"drizzle-kit": "^0.31.10", "drizzle-kit": "^0.31.10",
"esbuild": "^0.27.4", "esbuild": "^0.27.4",
"eslint": "^9.39.4", "eslint": "^9.39.4",
+258 -92
View File
@@ -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
@@ -310,8 +316,8 @@ importers:
specifier: ^2.22.2 specifier: ^2.22.2
version: 2.22.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(typescript@5.9.3)(zod@3.25.76) version: 2.22.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(typescript@5.9.3)(zod@3.25.76)
baseline-browser-mapping: baseline-browser-mapping:
specifier: ^2.10.11 specifier: ^2.10.12
version: 2.10.11 version: 2.10.12
drizzle-kit: drizzle-kit:
specifier: ^0.31.10 specifier: ^0.31.10
version: 0.31.10 version: 0.31.10
@@ -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'}
@@ -2033,8 +2042,8 @@ packages:
'@prisma/config@6.7.0': '@prisma/config@6.7.0':
resolution: {integrity: sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==} resolution: {integrity: sha512-di8QDdvSz7DLUi3OOcCHSwxRNeW7jtGRUD2+Z3SdNE3A+pPiNT8WgUJoUyOwJmUr5t+JA2W15P78C/N+8RXrOA==}
'@prisma/config@7.5.0': '@prisma/config@7.6.0':
resolution: {integrity: sha512-1J/9YEX7A889xM46PYg9e8VAuSL1IUmXJW3tEhMv7XQHDWlfC9YSkIw9sTYRaq5GswGlxZ+GnnyiNsUZ9JJhSQ==} resolution: {integrity: sha512-MuAz1MK4PeG5/03YzfzX3CnFVHQ6qePGwUpQRzPzX5tT0ffJ3Tzi9zJZbBc+VzEGFCM8ghW/gTVDR85Syjt+Yw==}
'@prisma/debug@6.19.2': '@prisma/debug@6.19.2':
resolution: {integrity: sha512-lFnEZsLdFLmEVCVNdskLDCL8Uup41GDfU0LUfquw+ercJC8ODTuL0WNKgOKmYxCJVvFwf0OuZBzW99DuWmoH2A==} resolution: {integrity: sha512-lFnEZsLdFLmEVCVNdskLDCL8Uup41GDfU0LUfquw+ercJC8ODTuL0WNKgOKmYxCJVvFwf0OuZBzW99DuWmoH2A==}
@@ -2042,8 +2051,8 @@ packages:
'@prisma/debug@6.7.0': '@prisma/debug@6.7.0':
resolution: {integrity: sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==} resolution: {integrity: sha512-RabHn9emKoYFsv99RLxvfG2GHzWk2ZI1BuVzqYtmMSIcuGboHY5uFt3Q3boOREM9de6z5s3bQoyKeWnq8Fz22w==}
'@prisma/debug@7.5.0': '@prisma/debug@7.6.0':
resolution: {integrity: sha512-163+nffny0JoPEkDhfNco0vcuT3ymIJc9+WX7MHSQhfkeKUmKe9/wqvGk5SjppT93DtBjVwr5HPJYlXbzm6qtg==} resolution: {integrity: sha512-LpHr3qos4lQZ6sxwjStf59YBht7m9/QF7NSQsMH6qGENWZu2w3UkQUGn1h5iRkDjnWRj3VHykOu9qFhps4ADvA==}
'@prisma/dmmf@6.19.2': '@prisma/dmmf@6.19.2':
resolution: {integrity: sha512-ZHGDQlnrWKwFPAOvJ8hVbmIqNPdE0XXptTeYqmUGhYMDySSts60O8g3KNY1uAqr3nHiyDcpaGIpO1MBYoDW6gQ==} resolution: {integrity: sha512-ZHGDQlnrWKwFPAOvJ8hVbmIqNPdE0XXptTeYqmUGhYMDySSts60O8g3KNY1uAqr3nHiyDcpaGIpO1MBYoDW6gQ==}
@@ -2051,8 +2060,8 @@ packages:
'@prisma/dmmf@6.7.0': '@prisma/dmmf@6.7.0':
resolution: {integrity: sha512-Nabzf5H7KUwYV/1u8R5gTQ7x3ffdPIhtxVJsjhnLOjeuem8YzVu39jOgQbiOlfOvjU4sPYkV9wEXc5tIHumdUw==} resolution: {integrity: sha512-Nabzf5H7KUwYV/1u8R5gTQ7x3ffdPIhtxVJsjhnLOjeuem8YzVu39jOgQbiOlfOvjU4sPYkV9wEXc5tIHumdUw==}
'@prisma/dmmf@7.5.0': '@prisma/dmmf@7.6.0':
resolution: {integrity: sha512-MAIM8Uji/UuT6PokBwfOHtLHV2GTPpeAwcaFDqNvSZR+rbxrV/gJeLuOjmSnFkGpro/Y0un4oxAkUO7mGQeY6g==} resolution: {integrity: sha512-OZFEOEziUnJJMx2vu3twM5jEIsEyCRDPXq2Y/2XMBNPhnscKvbDWS3DAYyWmH8jqkDn4VqyE1UCvEFt30Pqbww==}
'@prisma/driver-adapter-utils@6.19.2': '@prisma/driver-adapter-utils@6.19.2':
resolution: {integrity: sha512-tkHsL3jhx81eXg2oqtJH/1IEs8uEeUb1RpqHtwYqdNb176u9D0mnHRZM1/cKca/XhLpq49Nnd9XDxdMfWcKAYA==} resolution: {integrity: sha512-tkHsL3jhx81eXg2oqtJH/1IEs8uEeUb1RpqHtwYqdNb176u9D0mnHRZM1/cKca/XhLpq49Nnd9XDxdMfWcKAYA==}
@@ -2060,8 +2069,8 @@ packages:
'@prisma/driver-adapter-utils@6.7.0': '@prisma/driver-adapter-utils@6.7.0':
resolution: {integrity: sha512-xYcXALWz1GsCRqwcDw0kP0R27chn99Co/HMX0nyOvIjAOo+41Tl/qcCOce/Ik1wNMGTI68N64kt3iccJ4EJoCQ==} resolution: {integrity: sha512-xYcXALWz1GsCRqwcDw0kP0R27chn99Co/HMX0nyOvIjAOo+41Tl/qcCOce/Ik1wNMGTI68N64kt3iccJ4EJoCQ==}
'@prisma/driver-adapter-utils@7.5.0': '@prisma/driver-adapter-utils@7.6.0':
resolution: {integrity: sha512-B79N/amgV677mFesFDBAdrW0OIaqawap9E0sjgLBtzIz2R3hIMS1QB8mLZuUEiS4q5Y8Oh3I25Kw4SLxMypk9Q==} resolution: {integrity: sha512-D8j3p0RnhLuufMaRLX6QqtGgPC5Ao3l5oFP6Q5AL0rTHi4vna+NzGEipwCsfvcSvaGFCbsH3lsTMbb4WvY+ovA==}
'@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': '@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed':
resolution: {integrity: sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==} resolution: {integrity: sha512-EvpOFEWf1KkJpDsBCrih0kg3HdHuaCnXmMn7XFPObpFTzagK1N0Q0FMnYPsEhvARfANP5Ok11QyoTIRA2hgJTA==}
@@ -2069,8 +2078,8 @@ packages:
'@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7':
resolution: {integrity: sha512-03bgb1VD5gvuumNf+7fVGBzfpJPjmqV423l/WxsWk2cNQ42JD0/SsFBPhN6z8iAvdHs07/7ei77SKu7aZfq8bA==} resolution: {integrity: sha512-03bgb1VD5gvuumNf+7fVGBzfpJPjmqV423l/WxsWk2cNQ42JD0/SsFBPhN6z8iAvdHs07/7ei77SKu7aZfq8bA==}
'@prisma/engines-version@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711':
resolution: {integrity: sha512-E+iRV/vbJLl8iGjVr6g/TEWokA+gjkV/doZkaQN1i/ULVdDwGnPJDfLUIFGS3BVwlG/m6L8T4x1x5isl8hGMxA==} resolution: {integrity: sha512-r51DLcJ8bDRSrBEJF3J4cinoWyGA7rfP2mG6lD90VqIbGNOkbfcLcXalSVjq5Y6brQS3vcjrq4GbyUb1Cb7vkw==}
'@prisma/engines@6.19.2': '@prisma/engines@6.19.2':
resolution: {integrity: sha512-TTkJ8r+uk/uqczX40wb+ODG0E0icVsMgwCTyTHXehaEfb0uo80M9g1aW1tEJrxmFHeOZFXdI2sTA1j1AgcHi4A==} resolution: {integrity: sha512-TTkJ8r+uk/uqczX40wb+ODG0E0icVsMgwCTyTHXehaEfb0uo80M9g1aW1tEJrxmFHeOZFXdI2sTA1j1AgcHi4A==}
@@ -2078,8 +2087,8 @@ packages:
'@prisma/engines@6.7.0': '@prisma/engines@6.7.0':
resolution: {integrity: sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==} resolution: {integrity: sha512-3wDMesnOxPrOsq++e5oKV9LmIiEazFTRFZrlULDQ8fxdub5w4NgRBoxtWbvXmj2nJVCnzuz6eFix3OhIqsZ1jw==}
'@prisma/engines@7.5.0': '@prisma/engines@7.6.0':
resolution: {integrity: sha512-ondGRhzoaVpRWvFaQ5wH5zS1BIbhzbKqczKjCn6j3L0Zfe/LInjcEg8+xtB49AuZBX30qyx1ZtGoootUohz2pw==} resolution: {integrity: sha512-Sn5edRzhHqgRV2M+A0eIbY442B4mReWWf3pKs/LKreYgW7oa/up8JtK/s4iv/EQA097cyboZ08mmkpbLp+tZ3w==}
'@prisma/fetch-engine@6.19.2': '@prisma/fetch-engine@6.19.2':
resolution: {integrity: sha512-h4Ff4Pho+SR1S8XerMCC12X//oY2bG3Iug/fUnudfcXEUnIeRiBdXHFdGlGOgQ3HqKgosTEhkZMvGM9tWtYC+Q==} resolution: {integrity: sha512-h4Ff4Pho+SR1S8XerMCC12X//oY2bG3Iug/fUnudfcXEUnIeRiBdXHFdGlGOgQ3HqKgosTEhkZMvGM9tWtYC+Q==}
@@ -2087,8 +2096,8 @@ packages:
'@prisma/fetch-engine@6.7.0': '@prisma/fetch-engine@6.7.0':
resolution: {integrity: sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==} resolution: {integrity: sha512-zLlAGnrkmioPKJR4Yf7NfW3hftcvqeNNEHleMZK9yX7RZSkhmxacAYyfGsCcqRt47jiZ7RKdgE0Wh2fWnm7WsQ==}
'@prisma/fetch-engine@7.5.0': '@prisma/fetch-engine@7.6.0':
resolution: {integrity: sha512-kZCl2FV54qnyrVdnII8MI6qvt7HfU6Cbiz8dZ8PXz4f4lbSw45jEB9/gEMK2SGdiNhBKyk/Wv95uthoLhGMLYA==} resolution: {integrity: sha512-N575Ni95c3FkduWY/eKTHqNYgNbceZ1tQaSknVtJjpKmiiBXmniESn/GTxsDvICC4ZeiNrXxioGInzQrCdx16w==}
'@prisma/generator-helper@6.19.2': '@prisma/generator-helper@6.19.2':
resolution: {integrity: sha512-vSjDbHhtKjRDgywTDYyAJLEe+kMxq4DNLNiurk/tGca8W/H7duX4Z4UdvYXcv3kWmmgJJmdndh41dgIsrewa3w==} resolution: {integrity: sha512-vSjDbHhtKjRDgywTDYyAJLEe+kMxq4DNLNiurk/tGca8W/H7duX4Z4UdvYXcv3kWmmgJJmdndh41dgIsrewa3w==}
@@ -2096,8 +2105,8 @@ packages:
'@prisma/generator-helper@6.7.0': '@prisma/generator-helper@6.7.0':
resolution: {integrity: sha512-z4ey7n8eUFx7Ol7RJCoEo9SVK2roy80qLXdrUFlmswcs0e/z03wDl4tpaA02BE2Yi9KCZl2Tkd6oMes81vUefA==} resolution: {integrity: sha512-z4ey7n8eUFx7Ol7RJCoEo9SVK2roy80qLXdrUFlmswcs0e/z03wDl4tpaA02BE2Yi9KCZl2Tkd6oMes81vUefA==}
'@prisma/generator-helper@7.5.0': '@prisma/generator-helper@7.6.0':
resolution: {integrity: sha512-qxV/cqoGyKpt9sKlH5k2FoMlpo7gr/dnb2QvCfOaeWYEFanKQLjRE4lr5MovCq3ihfW5oeOpwuiSqz5SG5nlJg==} resolution: {integrity: sha512-Wnb7NypN2581AXsaDdfGM6Guvfg6ahs0ooWHhFwD+/mrE3rI122cNRWMV9W1hqyt5OITs+3TV2M6GZZ16NcwjQ==}
'@prisma/generator@6.19.2': '@prisma/generator@6.19.2':
resolution: {integrity: sha512-2xDQQUJh2s6Ty9I9CIGRz7Z8pEGxKxjU/lkFyLI5f83fDoISUaGhWQZGW35xMqKVDoNRM93w1ghm+1ScRy0mAA==} resolution: {integrity: sha512-2xDQQUJh2s6Ty9I9CIGRz7Z8pEGxKxjU/lkFyLI5f83fDoISUaGhWQZGW35xMqKVDoNRM93w1ghm+1ScRy0mAA==}
@@ -2105,8 +2114,8 @@ packages:
'@prisma/generator@6.7.0': '@prisma/generator@6.7.0':
resolution: {integrity: sha512-wCsD7QJn1JBKJfv5uOMhwBCvZPGerPJ3EC2HocFPFaHSzVIXLi/zNb/8gpBxervOXTbQRJ2dpqvMsJnwAnPi8A==} resolution: {integrity: sha512-wCsD7QJn1JBKJfv5uOMhwBCvZPGerPJ3EC2HocFPFaHSzVIXLi/zNb/8gpBxervOXTbQRJ2dpqvMsJnwAnPi8A==}
'@prisma/generator@7.5.0': '@prisma/generator@7.6.0':
resolution: {integrity: sha512-GwXeQQ3PFN6EPLCXN8lNjQfC1ssE7wm8AMm7kR8Xbi00REiBn7rB4G5QieW1Nv7zl9rqrpAfG5gfOUU0GAaA+w==} resolution: {integrity: sha512-F09ZN/QVlKuvoAKEnHZB3LBbooKQTrio7NrKhI7tf0C9XZuCoALP/F7gADpTayXDmPaII1Klit3SJmJsfantEw==}
'@prisma/get-platform@6.19.2': '@prisma/get-platform@6.19.2':
resolution: {integrity: sha512-PGLr06JUSTqIvztJtAzIxOwtWKtJm5WwOG6xpsgD37Rc84FpfUBGLKz65YpJBGtkRQGXTYEFie7pYALocC3MtA==} resolution: {integrity: sha512-PGLr06JUSTqIvztJtAzIxOwtWKtJm5WwOG6xpsgD37Rc84FpfUBGLKz65YpJBGtkRQGXTYEFie7pYALocC3MtA==}
@@ -2114,8 +2123,8 @@ packages:
'@prisma/get-platform@6.7.0': '@prisma/get-platform@6.7.0':
resolution: {integrity: sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==} resolution: {integrity: sha512-i9IH5lO4fQwnMLvQLYNdgVh9TK3PuWBfQd7QLk/YurnAIg+VeADcZDbmhAi4XBBDD+hDif9hrKyASu0hbjwabw==}
'@prisma/get-platform@7.5.0': '@prisma/get-platform@7.6.0':
resolution: {integrity: sha512-7I+2y1nu/gkEKSiHHbcZ1HPe/euGdEqJZxEEMT0246q4De1+hla0ZzlTgvaT9dHcVCgLSuCG8v39db5qUUWNgw==} resolution: {integrity: sha512-ohZDwXvtmnbzOcutR2D13lDWpZP1wQjmPyztmt0AwXLzQI7q95EE7NYCvS+M6N6SivT+BM0NOqLmTH3wms4L3A==}
'@prisma/internals@6.19.2': '@prisma/internals@6.19.2':
resolution: {integrity: sha512-ciXNy15WKIg4rjuA0dNZ03CMJEneoEi47a3E6Yp59KI90M7r/nieaiqSRtWakl9nKj2YKfRX6nraYC3zaeSQXQ==} resolution: {integrity: sha512-ciXNy15WKIg4rjuA0dNZ03CMJEneoEi47a3E6Yp59KI90M7r/nieaiqSRtWakl9nKj2YKfRX6nraYC3zaeSQXQ==}
@@ -2133,8 +2142,8 @@ packages:
typescript: typescript:
optional: true optional: true
'@prisma/internals@7.5.0': '@prisma/internals@7.6.0':
resolution: {integrity: sha512-c+W0pr0qBa1Zdw5iVnSKSGC6NtTD4HPBB8L5YNxg1OBvj3ZoCnZZZRseDSDTt3Dy7MneTlYon4M/NndBSZaXtA==} resolution: {integrity: sha512-0Q5B32twK3csXNiu+frqsrRODQJxYdMxdYeLSKpjCwWkTZyHRkIv+/zhUxp85zAHOM56H1Q0eieIcK7hKqPhnA==}
peerDependencies: peerDependencies:
typescript: '>=5.4.0' typescript: '>=5.4.0'
peerDependenciesMeta: peerDependenciesMeta:
@@ -2147,8 +2156,8 @@ packages:
'@prisma/prisma-schema-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': '@prisma/prisma-schema-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7':
resolution: {integrity: sha512-/5JrsJQAOIWSl+9WMM/0ugd737kT9zdMNr7EFaP7ogeMxAhxQ78uaOV6JYGEocD8LC0gZx7MXmVE/CTfYdJ2iA==} resolution: {integrity: sha512-/5JrsJQAOIWSl+9WMM/0ugd737kT9zdMNr7EFaP7ogeMxAhxQ78uaOV6JYGEocD8LC0gZx7MXmVE/CTfYdJ2iA==}
'@prisma/prisma-schema-wasm@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': '@prisma/prisma-schema-wasm@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711':
resolution: {integrity: sha512-d96xJBWAC/NcnoducHu+vW0C+00C9ZKEeA9Ly5oUBr40nO865nOzG9cyJ1O0N97tDUj+S2AbzTyrkFWAWYy3rQ==} resolution: {integrity: sha512-sGWZsHVJlxX/lDZiwFg00kyZGwZo3vwN4v5jaMus+7j1763SsXjrW1MSykDUZoy8W1Ent9kCyPRpu9dy/ajnIg==}
'@prisma/schema-engine-wasm@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': '@prisma/schema-engine-wasm@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed':
resolution: {integrity: sha512-BMdbaajhV46xPBEqwV/7pxYR67hA02ywUcKDKTIULhaofdbhCUee/O0zqoG4TmgsQZc3DUdwK7nmh2U7Ndj3fA==} resolution: {integrity: sha512-BMdbaajhV46xPBEqwV/7pxYR67hA02ywUcKDKTIULhaofdbhCUee/O0zqoG4TmgsQZc3DUdwK7nmh2U7Ndj3fA==}
@@ -2156,8 +2165,8 @@ packages:
'@prisma/schema-engine-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': '@prisma/schema-engine-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7':
resolution: {integrity: sha512-mXtzeePkSdqpr/HAIclqzQEf+tBzLawy7NQ9AaRCfg8N/cruavpsocgbSwOOfV7JTk9JubyzKuR3tp2bNNuWbQ==} resolution: {integrity: sha512-mXtzeePkSdqpr/HAIclqzQEf+tBzLawy7NQ9AaRCfg8N/cruavpsocgbSwOOfV7JTk9JubyzKuR3tp2bNNuWbQ==}
'@prisma/schema-engine-wasm@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': '@prisma/schema-engine-wasm@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711':
resolution: {integrity: sha512-dtTC5tVBTpOAXHEhoRYm/TQzC+kzzt6H8x1CUu99vVP6G7gN7tdO9FyykvY6+m5/P/qrrZZm9uHuXqJGV8l4UA==} resolution: {integrity: sha512-FNs45iHWzdmWL7NzZx2L1GUX1bIQuTjGBlLwDzlgwFx4jWZ3D3y7e5zDWq8MYY2GZzbRDfH2eTVzD0cKhLp5BQ==}
'@prisma/schema-files-loader@6.19.2': '@prisma/schema-files-loader@6.19.2':
resolution: {integrity: sha512-v4dHwmYn0rsn6E6Lo6EH4oT7rYVlbJTKWUL3j4gjX0AyQefm3NIITFdYuonDy1S4y2Z/3D1r8gCVjFLskKfK/A==} resolution: {integrity: sha512-v4dHwmYn0rsn6E6Lo6EH4oT7rYVlbJTKWUL3j4gjX0AyQefm3NIITFdYuonDy1S4y2Z/3D1r8gCVjFLskKfK/A==}
@@ -2165,8 +2174,8 @@ packages:
'@prisma/schema-files-loader@6.7.0': '@prisma/schema-files-loader@6.7.0':
resolution: {integrity: sha512-JaAu/hcMAX6rEhB48wTTyTqo7BNS2Cw8ReTGdqIHXJlBHz4p1HxvoqYcmJw/WEsjUx07J0L7RgQJhhbJpo1cdQ==} resolution: {integrity: sha512-JaAu/hcMAX6rEhB48wTTyTqo7BNS2Cw8ReTGdqIHXJlBHz4p1HxvoqYcmJw/WEsjUx07J0L7RgQJhhbJpo1cdQ==}
'@prisma/schema-files-loader@7.5.0': '@prisma/schema-files-loader@7.6.0':
resolution: {integrity: sha512-H6D2ldMIn+v1s6fxSX0flwGo54Rtj14mXNbSvMtx/Er45TIgyuaGbRSOMgAckU94FC4DR2uNbmFttTwTvz3ENA==} resolution: {integrity: sha512-D5JZLfDQyWPqit3lxNbGCxHSTQwJ2bB9lY6navoYYdL6lulPgsMj5+atAYaWF5hP4Akibr33CS3HZFZlUfH8IQ==}
'@protobufjs/aspromise@1.1.2': '@protobufjs/aspromise@1.1.2':
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
@@ -3043,6 +3052,9 @@ packages:
'@standard-schema/utils@0.3.0': '@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
'@streamparser/json@0.0.22':
resolution: {integrity: sha512-b6gTSBjJ8G8SuO3Gbbj+zXbVx8NSs1EbpbMKpzGLWMdkR+98McH9bEjSz3+0mPJf68c5nxa3CrJHp5EQNXM6zQ==}
'@swc/helpers@0.5.15': '@swc/helpers@0.5.15':
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
@@ -3719,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'}
@@ -3756,8 +3772,8 @@ packages:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9} engines: {node: ^4.5.0 || >= 5.9}
baseline-browser-mapping@2.10.11: baseline-browser-mapping@2.10.12:
resolution: {integrity: sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==} resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
@@ -3864,11 +3880,11 @@ packages:
boolbase@1.0.0: boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
brace-expansion@1.1.12: brace-expansion@1.1.13:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
brace-expansion@2.0.2: brace-expansion@2.0.3:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==}
brace-expansion@5.0.5: brace-expansion@5.0.5:
resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
@@ -4074,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'}
@@ -4263,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'}
@@ -4513,8 +4535,11 @@ packages:
effect@3.18.4: effect@3.18.4:
resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==}
electron-to-chromium@1.5.325: effect@3.20.0:
resolution: {integrity: sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==} resolution: {integrity: sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==}
electron-to-chromium@1.5.328:
resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==}
embla-carousel-react@8.6.0: embla-carousel-react@8.6.0:
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==} resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
@@ -4824,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==}
@@ -4848,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==}
@@ -5098,8 +5129,8 @@ packages:
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
handlebars@4.7.8: handlebars@4.7.9:
resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==}
engines: {node: '>=0.4.7'} engines: {node: '>=0.4.7'}
hasBin: true hasBin: true
@@ -5137,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==}
@@ -5442,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==}
@@ -6062,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==}
@@ -6246,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'}
@@ -6368,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'}
@@ -6420,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==}
@@ -6557,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==}
@@ -6662,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==}
@@ -6682,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==}
@@ -6796,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:
@@ -6936,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==}
@@ -7038,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==}
@@ -8863,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
@@ -8888,11 +8974,11 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@prisma/config@7.5.0': '@prisma/config@7.6.0':
dependencies: dependencies:
c12: 3.1.0 c12: 3.1.0
deepmerge-ts: 7.1.5 deepmerge-ts: 7.1.5
effect: 3.18.4 effect: 3.20.0
empathic: 2.0.0 empathic: 2.0.0
transitivePeerDependencies: transitivePeerDependencies:
- magicast - magicast
@@ -8901,13 +8987,13 @@ snapshots:
'@prisma/debug@6.7.0': {} '@prisma/debug@6.7.0': {}
'@prisma/debug@7.5.0': {} '@prisma/debug@7.6.0': {}
'@prisma/dmmf@6.19.2': {} '@prisma/dmmf@6.19.2': {}
'@prisma/dmmf@6.7.0': {} '@prisma/dmmf@6.7.0': {}
'@prisma/dmmf@7.5.0': {} '@prisma/dmmf@7.6.0': {}
'@prisma/driver-adapter-utils@6.19.2': '@prisma/driver-adapter-utils@6.19.2':
dependencies: dependencies:
@@ -8917,15 +9003,15 @@ snapshots:
dependencies: dependencies:
'@prisma/debug': 6.7.0 '@prisma/debug': 6.7.0
'@prisma/driver-adapter-utils@7.5.0': '@prisma/driver-adapter-utils@7.6.0':
dependencies: dependencies:
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': {} '@prisma/engines-version@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': {}
'@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {}
'@prisma/engines-version@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': {} '@prisma/engines-version@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': {}
'@prisma/engines@6.19.2': '@prisma/engines@6.19.2':
dependencies: dependencies:
@@ -8941,12 +9027,12 @@ snapshots:
'@prisma/fetch-engine': 6.7.0 '@prisma/fetch-engine': 6.7.0
'@prisma/get-platform': 6.7.0 '@prisma/get-platform': 6.7.0
'@prisma/engines@7.5.0': '@prisma/engines@7.6.0':
dependencies: dependencies:
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/engines-version': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711
'@prisma/fetch-engine': 7.5.0 '@prisma/fetch-engine': 7.6.0
'@prisma/get-platform': 7.5.0 '@prisma/get-platform': 7.6.0
'@prisma/fetch-engine@6.19.2': '@prisma/fetch-engine@6.19.2':
dependencies: dependencies:
@@ -8960,11 +9046,11 @@ snapshots:
'@prisma/engines-version': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed '@prisma/engines-version': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed
'@prisma/get-platform': 6.7.0 '@prisma/get-platform': 6.7.0
'@prisma/fetch-engine@7.5.0': '@prisma/fetch-engine@7.6.0':
dependencies: dependencies:
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/engines-version': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e '@prisma/engines-version': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711
'@prisma/get-platform': 7.5.0 '@prisma/get-platform': 7.6.0
'@prisma/generator-helper@6.19.2': '@prisma/generator-helper@6.19.2':
dependencies: dependencies:
@@ -8978,17 +9064,17 @@ snapshots:
'@prisma/dmmf': 6.7.0 '@prisma/dmmf': 6.7.0
'@prisma/generator': 6.7.0 '@prisma/generator': 6.7.0
'@prisma/generator-helper@7.5.0': '@prisma/generator-helper@7.6.0':
dependencies: dependencies:
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/dmmf': 7.5.0 '@prisma/dmmf': 7.6.0
'@prisma/generator': 7.5.0 '@prisma/generator': 7.6.0
'@prisma/generator@6.19.2': {} '@prisma/generator@6.19.2': {}
'@prisma/generator@6.7.0': {} '@prisma/generator@6.7.0': {}
'@prisma/generator@7.5.0': {} '@prisma/generator@7.6.0': {}
'@prisma/get-platform@6.19.2': '@prisma/get-platform@6.19.2':
dependencies: dependencies:
@@ -8998,9 +9084,9 @@ snapshots:
dependencies: dependencies:
'@prisma/debug': 6.7.0 '@prisma/debug': 6.7.0
'@prisma/get-platform@7.5.0': '@prisma/get-platform@7.6.0':
dependencies: dependencies:
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/internals@6.19.2(typescript@5.9.3)': '@prisma/internals@6.19.2(typescript@5.9.3)':
dependencies: dependencies:
@@ -9044,20 +9130,21 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@prisma/internals@7.5.0(typescript@5.9.3)': '@prisma/internals@7.6.0(typescript@5.9.3)':
dependencies: dependencies:
'@prisma/config': 7.5.0 '@prisma/config': 7.6.0
'@prisma/debug': 7.5.0 '@prisma/debug': 7.6.0
'@prisma/dmmf': 7.5.0 '@prisma/dmmf': 7.6.0
'@prisma/driver-adapter-utils': 7.5.0 '@prisma/driver-adapter-utils': 7.6.0
'@prisma/engines': 7.5.0 '@prisma/engines': 7.6.0
'@prisma/fetch-engine': 7.5.0 '@prisma/fetch-engine': 7.6.0
'@prisma/generator': 7.5.0 '@prisma/generator': 7.6.0
'@prisma/generator-helper': 7.5.0 '@prisma/generator-helper': 7.6.0
'@prisma/get-platform': 7.5.0 '@prisma/get-platform': 7.6.0
'@prisma/prisma-schema-wasm': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e '@prisma/prisma-schema-wasm': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711
'@prisma/schema-engine-wasm': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e '@prisma/schema-engine-wasm': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711
'@prisma/schema-files-loader': 7.5.0 '@prisma/schema-files-loader': 7.6.0
'@streamparser/json': 0.0.22
arg: 5.0.2 arg: 5.0.2
prompts: 2.4.2 prompts: 2.4.2
optionalDependencies: optionalDependencies:
@@ -9069,13 +9156,13 @@ snapshots:
'@prisma/prisma-schema-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} '@prisma/prisma-schema-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {}
'@prisma/prisma-schema-wasm@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': {} '@prisma/prisma-schema-wasm@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': {}
'@prisma/schema-engine-wasm@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': {} '@prisma/schema-engine-wasm@6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed': {}
'@prisma/schema-engine-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} '@prisma/schema-engine-wasm@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {}
'@prisma/schema-engine-wasm@7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e': {} '@prisma/schema-engine-wasm@7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711': {}
'@prisma/schema-files-loader@6.19.2': '@prisma/schema-files-loader@6.19.2':
dependencies: dependencies:
@@ -9087,9 +9174,9 @@ snapshots:
'@prisma/prisma-schema-wasm': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed '@prisma/prisma-schema-wasm': 6.7.0-36.3cff47a7f5d65c3ea74883f1d736e41d68ce91ed
fs-extra: 11.3.0 fs-extra: 11.3.0
'@prisma/schema-files-loader@7.5.0': '@prisma/schema-files-loader@7.6.0':
dependencies: dependencies:
'@prisma/prisma-schema-wasm': 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e '@prisma/prisma-schema-wasm': 7.6.0-1.75cbdc1eb7150937890ad5465d861175c6624711
fs-extra: 11.3.0 fs-extra: 11.3.0
'@protobufjs/aspromise@1.1.2': {} '@protobufjs/aspromise@1.1.2': {}
@@ -10400,6 +10487,8 @@ snapshots:
'@standard-schema/utils@0.3.0': {} '@standard-schema/utils@0.3.0': {}
'@streamparser/json@0.0.22': {}
'@swc/helpers@0.5.15': '@swc/helpers@0.5.15':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@@ -10993,7 +11082,7 @@ snapshots:
dependencies: dependencies:
'@prisma/generator-helper': 6.19.2 '@prisma/generator-helper': 6.19.2
'@prisma/internals': 6.19.2(typescript@5.9.3) '@prisma/internals': 6.19.2(typescript@5.9.3)
'@prisma/internals-v7': '@prisma/internals@7.5.0(typescript@5.9.3)' '@prisma/internals-v7': '@prisma/internals@7.6.0(typescript@5.9.3)'
'@zenstackhq/language': 2.22.2 '@zenstackhq/language': 2.22.2
'@zenstackhq/runtime': 2.22.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(zod@3.25.76) '@zenstackhq/runtime': 2.22.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(zod@3.25.76)
langium: 1.3.1 langium: 1.3.1
@@ -11197,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):
@@ -11225,7 +11316,7 @@ snapshots:
base64id@2.0.0: {} base64id@2.0.0: {}
baseline-browser-mapping@2.10.11: {} baseline-browser-mapping@2.10.12: {}
basic-ftp@5.2.0: {} basic-ftp@5.2.0: {}
@@ -11308,12 +11399,12 @@ snapshots:
boolbase@1.0.0: {} boolbase@1.0.0: {}
brace-expansion@1.1.12: brace-expansion@1.1.13:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
concat-map: 0.0.1 concat-map: 0.0.1
brace-expansion@2.0.2: brace-expansion@2.0.3:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@@ -11329,9 +11420,9 @@ snapshots:
browserslist@4.28.1: browserslist@4.28.1:
dependencies: dependencies:
baseline-browser-mapping: 2.10.11 baseline-browser-mapping: 2.10.12
caniuse-lite: 1.0.30001781 caniuse-lite: 1.0.30001781
electron-to-chromium: 1.5.325 electron-to-chromium: 1.5.328
node-releases: 2.0.36 node-releases: 2.0.36
update-browserslist-db: 1.2.3(browserslist@4.28.1) update-browserslist-db: 1.2.3(browserslist@4.28.1)
@@ -11569,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: {}
@@ -11617,7 +11710,7 @@ snapshots:
dependencies: dependencies:
'@simple-libs/stream-utils': 1.2.0 '@simple-libs/stream-utils': 1.2.0
conventional-commits-filter: 5.0.0 conventional-commits-filter: 5.0.0
handlebars: 4.7.8 handlebars: 4.7.9
meow: 13.2.0 meow: 13.2.0
semver: 7.7.4 semver: 7.7.4
@@ -11761,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:
@@ -11927,7 +12022,12 @@ snapshots:
'@standard-schema/spec': 1.1.0 '@standard-schema/spec': 1.1.0
fast-check: 3.23.2 fast-check: 3.23.2
electron-to-chromium@1.5.325: {} effect@3.20.0:
dependencies:
'@standard-schema/spec': 1.1.0
fast-check: 3.23.2
electron-to-chromium@1.5.328: {}
embla-carousel-react@8.6.0(react@19.2.4): embla-carousel-react@8.6.0(react@19.2.4):
dependencies: dependencies:
@@ -12493,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: {}
@@ -12519,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:
@@ -12786,7 +12890,7 @@ snapshots:
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
handlebars@4.7.8: handlebars@4.7.9:
dependencies: dependencies:
minimist: 1.2.8 minimist: 1.2.8
neo-async: 2.6.2 neo-async: 2.6.2
@@ -12824,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:
@@ -13124,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:
@@ -13390,11 +13498,11 @@ snapshots:
minimatch@3.1.5: minimatch@3.1.5:
dependencies: dependencies:
brace-expansion: 1.1.12 brace-expansion: 1.1.13
minimatch@5.1.9: minimatch@5.1.9:
dependencies: dependencies:
brace-expansion: 2.0.2 brace-expansion: 2.0.3
minimist@1.2.8: {} minimist@1.2.8: {}
@@ -13513,7 +13621,7 @@ snapshots:
dependencies: dependencies:
'@next/env': 16.2.1 '@next/env': 16.2.1
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.11 baseline-browser-mapping: 2.10.12
caniuse-lite: 1.0.30001781 caniuse-lite: 1.0.30001781
postcss: 8.4.31 postcss: 8.4.31
react: 19.2.4 react: 19.2.4
@@ -13662,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
@@ -13885,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:
@@ -13989,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
@@ -14062,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
@@ -14244,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
@@ -14389,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:
@@ -14415,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
@@ -14629,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
@@ -14786,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):
@@ -14913,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
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@@ -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
View File
@@ -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:");
} }
} }
} }
+1
View File
@@ -0,0 +1 @@
ALTER TYPE "public"."dbms_status" ADD VALUE 'mariadb' BEFORE 'mongodb';
@@ -0,0 +1 @@
ALTER TYPE "public"."dbms_status" ADD VALUE 'firebird';
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+14
View File
@@ -330,6 +330,20 @@
"when": 1774706071024, "when": 1774706071024,
"tag": "0046_mysterious_menace", "tag": "0046_mysterious_menace",
"breakpoints": true "breakpoints": true
},
{
"idx": 47,
"version": "7",
"when": 1774768062658,
"tag": "0047_wet_carnage",
"breakpoints": true
},
{
"idx": 48,
"version": "7",
"when": 1774886139855,
"tag": "0048_yellow_eddie_brock",
"breakpoints": true
} }
] ]
} }
+1 -1
View File
@@ -2,7 +2,7 @@ import {pgEnum} from "drizzle-orm/pg-core";
import {createSelectSchema} from "drizzle-zod"; import {createSelectSchema} from "drizzle-zod";
import {z} from "zod"; import {z} from "zod";
export const dbmsEnum = pgEnum("dbms_status", ["postgresql", "mysql", "mongodb", "sqlite", "redis", "valkey"]); export const dbmsEnum = pgEnum("dbms_status", ["postgresql", "mysql", "mariadb", "mongodb", "sqlite", "redis", "valkey", "firebird"]);
export const statusEnum = pgEnum("status", ["waiting", "ongoing", "failed", "success"]); export const statusEnum = pgEnum("status", ["waiting", "ongoing", "failed", "success"]);
export const typeStorageEnum = pgEnum("type_storage", ["local", "s3"]); export const typeStorageEnum = pgEnum("type_storage", ["local", "s3"]);
+7 -9
View File
@@ -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);
} }
} }
} }
} }
+4
View File
@@ -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,
+2 -1
View File
@@ -23,7 +23,7 @@ export async function sendNotificationsBackupRestore(database: DatabaseWith, eve
const policiesToUse = (database.alertPolicies && database.alertPolicies.length > 0) const policiesToUse = (database.alertPolicies && database.alertPolicies.length > 0)
? database.alertPolicies.filter(policy => policy.enabled && policy.eventKinds.includes(event)) ? database.alertPolicies.filter(policy => policy.enabled && policy.eventKinds.includes(event))
: defaultPolicy; : defaultPolicy.filter(policy => policy.eventKinds.includes(event));
if (!policiesToUse || policiesToUse.length === 0) { if (!policiesToUse || policiesToUse.length === 0) {
return []; return [];
@@ -60,6 +60,7 @@ export async function sendNotificationsBackupRestore(database: DatabaseWith, eve
success_restore: `Restore Notification`, success_restore: `Restore Notification`,
weekly_report: `Weekly Report Notification`, weekly_report: `Weekly Report Notification`,
error_health_agent: "Health Agent Notification", error_health_agent: "Health Agent Notification",
error_health_database: "Health Database Notification",
}; };
const payload: EventPayload = { const payload: EventPayload = {
+19 -1
View File
@@ -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: {
+46
View File
@@ -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
}
}
})
});
+5 -3
View File
@@ -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;
} }
}; };
+7 -3
View File
@@ -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);
+7 -5
View File
@@ -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}`);
} }
} }
} }
+7 -3
View File
@@ -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}`);
} }
} }
+6 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
} }