mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
fix: refactoring, adding express api.
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {eventEmitter} from "../../../events/route";
|
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {db} from "@/db";
|
import {db} from "@/db";
|
||||||
import {Backup} from "@/db/schema/07_database";
|
import {Backup} from "@/db/schema/07_database";
|
||||||
@@ -10,6 +9,7 @@ import {withUpdatedAt} from "@/db/utils";
|
|||||||
import {decryptedDump, getFileExtension} from "./helpers";
|
import {decryptedDump, getFileExtension} from "./helpers";
|
||||||
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||||
import {storeBackupFiles} from "@/features/storages/helpers";
|
import {storeBackupFiles} from "@/features/storages/helpers";
|
||||||
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
|
||||||
export async function POST(
|
export async function POST(
|
||||||
request: Request,
|
request: Request,
|
||||||
@@ -35,8 +35,6 @@ export async function POST(
|
|||||||
const method = formData.get("method") as string | null;
|
const method = formData.get("method") as string | null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!generatedId || !isUuidv4(generatedId)) {
|
if (!generatedId || !isUuidv4(generatedId)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "generatedId is not a valid UUID"},
|
{error: "generatedId is not a valid UUID"},
|
||||||
@@ -116,7 +114,6 @@ export async function POST(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "File is required for successful backup"},
|
{error: "File is required for successful backup"},
|
||||||
@@ -132,9 +129,6 @@ export async function POST(
|
|||||||
const buffer = Buffer.from(await decryptedFile.arrayBuffer());
|
const buffer = Buffer.from(await decryptedFile.arrayBuffer());
|
||||||
|
|
||||||
|
|
||||||
console.log(extension)
|
|
||||||
|
|
||||||
|
|
||||||
const storageResults = await storeBackupFiles(backup, database, buffer, fileName)
|
const storageResults = await storeBackupFiles(backup, database, buffer, fileName)
|
||||||
eventEmitter.emit('modification', {update: true});
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
@@ -173,4 +167,3 @@ export async function POST(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {isUuidv4} from "@/utils/verify-uuid";
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
import {eventEmitter} from "../../../events/route";
|
|
||||||
import * as drizzleDb from "@/db";
|
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";
|
||||||
|
|
||||||
export type BodyResultRestore = {
|
export type BodyResultRestore = {
|
||||||
generatedId: string
|
generatedId: string
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {NextResponse} from "next/server";
|
import {NextResponse} from "next/server";
|
||||||
import {handleDatabases} from "./helpers";
|
import {handleDatabases} from "./helpers";
|
||||||
import {eventEmitter} from "../../../events/route";
|
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {db} from "@/db";
|
import {db} from "@/db";
|
||||||
import {EDbmsSchema} from "@/db/schema/types";
|
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";
|
||||||
|
|
||||||
export type databaseAgent = {
|
export type databaseAgent = {
|
||||||
name: string,
|
name: string,
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import {EventEmitter} from 'events';
|
|||||||
import {auth} from "@/lib/auth/auth";
|
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";
|
||||||
|
|
||||||
export const eventEmitter = new EventEmitter();
|
// export const eventEmitter = new EventEmitter();
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,9 @@ export async function GET(
|
|||||||
const result = await dispatchStorage(input, undefined, storageId);
|
const result = await dispatchStorage(input, undefined, storageId);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return NextResponse.json({error: "Enable to get file from privided storage channel, an error occurred !"})
|
return NextResponse.json({error: "Enable to get file from provided storage channel, an error occurred !"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const fileName = path.basename(pathFromUrl);
|
const fileName = path.basename(pathFromUrl);
|
||||||
|
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
@@ -58,14 +57,14 @@ export async function GET(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.file || !Buffer.isBuffer(result.file)) {
|
if (!result.file || !(result.file instanceof Readable)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{error: "Invalid file payload"},
|
{error: "Invalid file payload"},
|
||||||
{status: 500}
|
{status: 500}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileStream = Readable.from(result.file);
|
const fileStream = Readable.from(result.file as Readable);
|
||||||
|
|
||||||
const stream = new ReadableStream({
|
const stream = new ReadableStream({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ else
|
|||||||
echo "[WARN] No TZ provided, using default container timezone"
|
echo "[WARN] No TZ provided, using default container timezone"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
node server/server.js
|
||||||
node server.js
|
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const nextConfig: NextConfig = {
|
|||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
experimental: {
|
experimental: {
|
||||||
serverActions: {
|
serverActions: {
|
||||||
bodySizeLimit: "10gb",
|
bodySizeLimit: "10gb",
|
||||||
|
|||||||
+8
-4
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "portabase",
|
"name": "portabase",
|
||||||
"version": "1.2.4-rc.2",
|
"version": "1.2.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack -p 8887",
|
"dev": "NODE_ENV=development tsx watch server/server.ts",
|
||||||
"build": "next build --experimental-build-mode compile",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "NODE_ENV=production node server/server.js",
|
||||||
|
|
||||||
|
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"email": "email dev --dir ./src/components/emails",
|
"email": "email dev --dir ./src/components/emails",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
@@ -47,6 +49,7 @@
|
|||||||
"@t3-oss/env-nextjs": "^0.13.4",
|
"@t3-oss/env-nextjs": "^0.13.4",
|
||||||
"@tanstack/react-query": "^5.76.1",
|
"@tanstack/react-query": "^5.76.1",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"@types/express": "^5.0.6",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@zenstackhq/runtime": "2.14.2",
|
"@zenstackhq/runtime": "2.14.2",
|
||||||
@@ -62,6 +65,7 @@
|
|||||||
"drizzle-orm": "^0.43.1",
|
"drizzle-orm": "^0.43.1",
|
||||||
"drizzle-zod": "^0.7.1",
|
"drizzle-zod": "^0.7.1",
|
||||||
"embla-carousel-react": "^8.6.0",
|
"embla-carousel-react": "^8.6.0",
|
||||||
|
"express": "^5.2.1",
|
||||||
"googleapis": "^170.1.0",
|
"googleapis": "^170.1.0",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.553.0",
|
"lucide-react": "^0.553.0",
|
||||||
|
|||||||
Generated
+403
-16
@@ -107,6 +107,9 @@ importers:
|
|||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.21.3
|
specifier: ^8.21.3
|
||||||
version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
|
'@types/express':
|
||||||
|
specifier: ^5.0.6
|
||||||
|
version: 5.0.6
|
||||||
'@types/nodemailer':
|
'@types/nodemailer':
|
||||||
specifier: ^6.4.17
|
specifier: ^6.4.17
|
||||||
version: 6.4.21
|
version: 6.4.21
|
||||||
@@ -124,7 +127,7 @@ importers:
|
|||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
better-auth:
|
better-auth:
|
||||||
specifier: 1.4.5
|
specifier: 1.4.5
|
||||||
version: 1.4.5(next@16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 1.4.5(next@16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.1
|
specifier: ^0.7.1
|
||||||
version: 0.7.1
|
version: 0.7.1
|
||||||
@@ -152,6 +155,9 @@ importers:
|
|||||||
embla-carousel-react:
|
embla-carousel-react:
|
||||||
specifier: ^8.6.0
|
specifier: ^8.6.0
|
||||||
version: 8.6.0(react@19.2.3)
|
version: 8.6.0(react@19.2.3)
|
||||||
|
express:
|
||||||
|
specifier: ^5.2.1
|
||||||
|
version: 5.2.1
|
||||||
googleapis:
|
googleapis:
|
||||||
specifier: ^170.1.0
|
specifier: ^170.1.0
|
||||||
version: 170.1.0
|
version: 170.1.0
|
||||||
@@ -169,10 +175,10 @@ importers:
|
|||||||
version: 12.24.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 12.24.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
next:
|
next:
|
||||||
specifier: 16.0.10
|
specifier: 16.0.10
|
||||||
version: 16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
next-safe-action:
|
next-safe-action:
|
||||||
specifier: ^7.10.8
|
specifier: ^7.10.8
|
||||||
version: 7.10.8(next@16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76)
|
version: 7.10.8(next@16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76)
|
||||||
next-themes:
|
next-themes:
|
||||||
specifier: ^0.4.6
|
specifier: ^0.4.6
|
||||||
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
@@ -3071,6 +3077,12 @@ packages:
|
|||||||
'@tybys/wasm-util@0.10.1':
|
'@tybys/wasm-util@0.10.1':
|
||||||
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
||||||
|
|
||||||
|
'@types/body-parser@1.19.6':
|
||||||
|
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
|
||||||
|
|
||||||
|
'@types/connect@3.4.38':
|
||||||
|
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||||
|
|
||||||
'@types/cors@2.8.19':
|
'@types/cors@2.8.19':
|
||||||
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
|
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
|
||||||
|
|
||||||
@@ -3113,6 +3125,15 @@ packages:
|
|||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/express-serve-static-core@5.1.1':
|
||||||
|
resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
|
||||||
|
|
||||||
|
'@types/express@5.0.6':
|
||||||
|
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
||||||
|
|
||||||
|
'@types/http-errors@2.0.5':
|
||||||
|
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
@@ -3143,6 +3164,12 @@ packages:
|
|||||||
'@types/prismjs@1.26.5':
|
'@types/prismjs@1.26.5':
|
||||||
resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
|
resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==}
|
||||||
|
|
||||||
|
'@types/qs@6.14.0':
|
||||||
|
resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==}
|
||||||
|
|
||||||
|
'@types/range-parser@1.2.7':
|
||||||
|
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||||
|
|
||||||
'@types/react-dom@19.0.4':
|
'@types/react-dom@19.0.4':
|
||||||
resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==}
|
resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3159,6 +3186,12 @@ packages:
|
|||||||
'@types/react@19.2.7':
|
'@types/react@19.2.7':
|
||||||
resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
|
resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
|
||||||
|
|
||||||
|
'@types/send@1.2.1':
|
||||||
|
resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
|
||||||
|
|
||||||
|
'@types/serve-static@2.2.0':
|
||||||
|
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
||||||
|
|
||||||
'@types/webpack@5.28.5':
|
'@types/webpack@5.28.5':
|
||||||
resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==}
|
resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==}
|
||||||
|
|
||||||
@@ -3420,6 +3453,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
accepts@2.0.0:
|
||||||
|
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
acorn-import-phases@1.0.4:
|
acorn-import-phases@1.0.4:
|
||||||
resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==}
|
resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
@@ -3657,6 +3694,10 @@ packages:
|
|||||||
block-stream2@2.1.0:
|
block-stream2@2.1.0:
|
||||||
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==}
|
||||||
|
|
||||||
|
body-parser@2.2.2:
|
||||||
|
resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
boolbase@1.0.0:
|
boolbase@1.0.0:
|
||||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||||
|
|
||||||
@@ -3701,6 +3742,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==}
|
resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
bytes@3.1.2:
|
||||||
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
c12@3.1.0:
|
c12@3.1.0:
|
||||||
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
|
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3856,9 +3901,21 @@ packages:
|
|||||||
constant-case@3.0.4:
|
constant-case@3.0.4:
|
||||||
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
|
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
|
||||||
|
|
||||||
|
content-disposition@1.0.1:
|
||||||
|
resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
content-type@1.0.5:
|
||||||
|
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
convert-source-map@2.0.0:
|
convert-source-map@2.0.0:
|
||||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||||
|
|
||||||
|
cookie-signature@1.2.2:
|
||||||
|
resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
|
||||||
|
engines: {node: '>=6.6.0'}
|
||||||
|
|
||||||
cookie@0.7.2:
|
cookie@0.7.2:
|
||||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -4028,6 +4085,10 @@ packages:
|
|||||||
defu@6.1.4:
|
defu@6.1.4:
|
||||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||||
|
|
||||||
|
depd@2.0.0:
|
||||||
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
destr@2.0.5:
|
destr@2.0.5:
|
||||||
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
||||||
|
|
||||||
@@ -4188,6 +4249,9 @@ packages:
|
|||||||
ecdsa-sig-formatter@1.0.11:
|
ecdsa-sig-formatter@1.0.11:
|
||||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||||
|
|
||||||
|
ee-first@1.1.1:
|
||||||
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||||
|
|
||||||
effect@3.18.4:
|
effect@3.18.4:
|
||||||
resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==}
|
resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==}
|
||||||
|
|
||||||
@@ -4223,6 +4287,10 @@ packages:
|
|||||||
emphasize@4.2.0:
|
emphasize@4.2.0:
|
||||||
resolution: {integrity: sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg==}
|
resolution: {integrity: sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg==}
|
||||||
|
|
||||||
|
encodeurl@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
end-of-stream@1.4.5:
|
end-of-stream@1.4.5:
|
||||||
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
|
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
|
||||||
|
|
||||||
@@ -4309,6 +4377,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
escape-html@1.0.3:
|
||||||
|
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||||
|
|
||||||
escape-string-regexp@4.0.0:
|
escape-string-regexp@4.0.0:
|
||||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -4443,6 +4514,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
etag@1.8.1:
|
||||||
|
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
eventemitter3@4.0.7:
|
eventemitter3@4.0.7:
|
||||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||||
|
|
||||||
@@ -4453,6 +4528,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||||
engines: {node: '>=0.8.x'}
|
engines: {node: '>=0.8.x'}
|
||||||
|
|
||||||
|
express@5.2.1:
|
||||||
|
resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
exsolve@1.0.8:
|
exsolve@1.0.8:
|
||||||
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
|
||||||
|
|
||||||
@@ -4533,6 +4612,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
|
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
finalhandler@2.1.1:
|
||||||
|
resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
|
||||||
|
engines: {node: '>= 18.0.0'}
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -4560,6 +4643,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||||
engines: {node: '>=12.20.0'}
|
engines: {node: '>=12.20.0'}
|
||||||
|
|
||||||
|
forwarded@0.2.0:
|
||||||
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
fraction.js@4.3.7:
|
fraction.js@4.3.7:
|
||||||
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
|
||||||
|
|
||||||
@@ -4591,6 +4678,10 @@ packages:
|
|||||||
react-dom:
|
react-dom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
fresh@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
fs-constants@1.0.0:
|
fs-constants@1.0.0:
|
||||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||||
|
|
||||||
@@ -4773,6 +4864,10 @@ packages:
|
|||||||
htmlparser2@8.0.2:
|
htmlparser2@8.0.2:
|
||||||
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
|
||||||
|
|
||||||
|
http-errors@2.0.1:
|
||||||
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
https-proxy-agent@5.0.0:
|
https-proxy-agent@5.0.0:
|
||||||
resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==}
|
resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@@ -4781,6 +4876,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
iconv-lite@0.7.2:
|
||||||
|
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
ieee754@1.2.1:
|
ieee754@1.2.1:
|
||||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
|
|
||||||
@@ -4817,6 +4916,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
|
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
ipaddr.js@1.9.1:
|
||||||
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
ipaddr.js@2.3.0:
|
ipaddr.js@2.3.0:
|
||||||
resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==}
|
resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
@@ -4912,6 +5015,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-promise@4.0.0:
|
||||||
|
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
||||||
|
|
||||||
is-regex@1.2.1:
|
is-regex@1.2.1:
|
||||||
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -5242,6 +5348,14 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18.0 || ^19.0
|
react: ^18.0 || ^19.0
|
||||||
|
|
||||||
|
media-typer@1.1.0:
|
||||||
|
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
merge-descriptors@2.0.0:
|
||||||
|
resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
merge-stream@2.0.0:
|
merge-stream@2.0.0:
|
||||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||||
|
|
||||||
@@ -5369,6 +5483,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
negotiator@1.0.0:
|
||||||
|
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
neo-async@2.6.2:
|
neo-async@2.6.2:
|
||||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
|
|
||||||
@@ -5557,6 +5675,10 @@ packages:
|
|||||||
ohash@2.0.11:
|
ohash@2.0.11:
|
||||||
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
|
||||||
|
|
||||||
|
on-finished@2.4.1:
|
||||||
|
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
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==}
|
||||||
|
|
||||||
@@ -5608,6 +5730,10 @@ packages:
|
|||||||
parseley@0.12.1:
|
parseley@0.12.1:
|
||||||
resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
|
resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
|
||||||
|
|
||||||
|
parseurl@1.3.3:
|
||||||
|
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
pascal-case@3.1.2:
|
pascal-case@3.1.2:
|
||||||
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
|
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
|
||||||
|
|
||||||
@@ -5636,6 +5762,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
|
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
|
path-to-regexp@8.3.0:
|
||||||
|
resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==}
|
||||||
|
|
||||||
pathe@2.0.3:
|
pathe@2.0.3:
|
||||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||||
|
|
||||||
@@ -5817,6 +5946,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
|
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
proxy-addr@2.0.7:
|
||||||
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
pump@3.0.3:
|
pump@3.0.3:
|
||||||
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
|
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
|
||||||
|
|
||||||
@@ -5844,6 +5977,14 @@ packages:
|
|||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
|
|
||||||
|
range-parser@1.2.1:
|
||||||
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
raw-body@3.0.2:
|
||||||
|
resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
rc9@2.1.2:
|
rc9@2.1.2:
|
||||||
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
|
||||||
|
|
||||||
@@ -6041,6 +6182,10 @@ packages:
|
|||||||
rou3@0.7.12:
|
rou3@0.7.12:
|
||||||
resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==}
|
resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==}
|
||||||
|
|
||||||
|
router@2.2.0:
|
||||||
|
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
run-parallel@1.2.0:
|
run-parallel@1.2.0:
|
||||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
|
|
||||||
@@ -6090,12 +6235,20 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
send@1.2.1:
|
||||||
|
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
sentence-case@3.0.4:
|
sentence-case@3.0.4:
|
||||||
resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
|
resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
|
||||||
|
|
||||||
serialize-javascript@6.0.2:
|
serialize-javascript@6.0.2:
|
||||||
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||||
|
|
||||||
|
serve-static@2.2.1:
|
||||||
|
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
set-cookie-parser@2.7.2:
|
set-cookie-parser@2.7.2:
|
||||||
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||||
|
|
||||||
@@ -6111,6 +6264,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
setprototypeof@1.2.0:
|
||||||
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
sharp@0.34.4:
|
sharp@0.34.4:
|
||||||
resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
|
resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
@@ -6226,6 +6382,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==}
|
resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
statuses@2.0.2:
|
||||||
|
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
stdin-discarder@0.2.2:
|
stdin-discarder@0.2.2:
|
||||||
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
|
resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -6428,6 +6588,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
|
|
||||||
|
toidentifier@1.0.1:
|
||||||
|
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||||
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
@@ -6486,6 +6650,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
|
resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
type-is@2.0.1:
|
||||||
|
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -6532,6 +6700,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
||||||
|
unpipe@1.0.0:
|
||||||
|
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
unrs-resolver@1.11.1:
|
unrs-resolver@1.11.1:
|
||||||
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
|
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
|
||||||
|
|
||||||
@@ -10035,6 +10207,15 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@types/body-parser@1.19.6':
|
||||||
|
dependencies:
|
||||||
|
'@types/connect': 3.4.38
|
||||||
|
'@types/node': 22.19.3
|
||||||
|
|
||||||
|
'@types/connect@3.4.38':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 22.19.3
|
||||||
|
|
||||||
'@types/cors@2.8.19':
|
'@types/cors@2.8.19':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.3
|
'@types/node': 22.19.3
|
||||||
@@ -10079,6 +10260,21 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/express-serve-static-core@5.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 22.19.3
|
||||||
|
'@types/qs': 6.14.0
|
||||||
|
'@types/range-parser': 1.2.7
|
||||||
|
'@types/send': 1.2.1
|
||||||
|
|
||||||
|
'@types/express@5.0.6':
|
||||||
|
dependencies:
|
||||||
|
'@types/body-parser': 1.19.6
|
||||||
|
'@types/express-serve-static-core': 5.1.1
|
||||||
|
'@types/serve-static': 2.2.0
|
||||||
|
|
||||||
|
'@types/http-errors@2.0.5': {}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
@@ -10116,6 +10312,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/prismjs@1.26.5': {}
|
'@types/prismjs@1.26.5': {}
|
||||||
|
|
||||||
|
'@types/qs@6.14.0': {}
|
||||||
|
|
||||||
|
'@types/range-parser@1.2.7': {}
|
||||||
|
|
||||||
'@types/react-dom@19.0.4(@types/react@19.0.10)':
|
'@types/react-dom@19.0.4(@types/react@19.0.10)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
@@ -10132,11 +10332,20 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
|
'@types/send@1.2.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 22.19.3
|
||||||
|
|
||||||
|
'@types/serve-static@2.2.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/http-errors': 2.0.5
|
||||||
|
'@types/node': 22.19.3
|
||||||
|
|
||||||
'@types/webpack@5.28.5(esbuild@0.25.10)':
|
'@types/webpack@5.28.5(esbuild@0.25.10)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.3
|
'@types/node': 22.19.3
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
webpack: 5.104.1(esbuild@0.25.10)
|
webpack: 5.104.1(esbuild@0.27.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@swc/core'
|
- '@swc/core'
|
||||||
- esbuild
|
- esbuild
|
||||||
@@ -10537,6 +10746,11 @@ snapshots:
|
|||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
negotiator: 0.6.3
|
negotiator: 0.6.3
|
||||||
|
|
||||||
|
accepts@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
mime-types: 3.0.2
|
||||||
|
negotiator: 1.0.0
|
||||||
|
|
||||||
acorn-import-phases@1.0.4(acorn@8.15.0):
|
acorn-import-phases@1.0.4(acorn@8.15.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.15.0
|
acorn: 8.15.0
|
||||||
@@ -10733,7 +10947,7 @@ snapshots:
|
|||||||
|
|
||||||
bcryptjs@2.4.3: {}
|
bcryptjs@2.4.3: {}
|
||||||
|
|
||||||
better-auth@1.4.5(next@16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
better-auth@1.4.5(next@16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@better-auth/core': 1.4.5(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.4(zod@3.25.76))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0)
|
'@better-auth/core': 1.4.5(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.4(zod@3.25.76))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0)
|
||||||
'@better-auth/telemetry': 1.4.5(@better-auth/core@1.4.5(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.4(zod@3.25.76))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0))
|
'@better-auth/telemetry': 1.4.5(@better-auth/core@1.4.5(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.4(zod@3.25.76))(jose@6.1.3)(kysely@0.28.9)(nanostores@1.1.0))
|
||||||
@@ -10749,7 +10963,7 @@ snapshots:
|
|||||||
nanostores: 1.1.0
|
nanostores: 1.1.0
|
||||||
zod: 4.3.5
|
zod: 4.3.5
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
next: 16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
next: 16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
|
|
||||||
@@ -10776,6 +10990,20 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
|
body-parser@2.2.2:
|
||||||
|
dependencies:
|
||||||
|
bytes: 3.1.2
|
||||||
|
content-type: 1.0.5
|
||||||
|
debug: 4.4.3
|
||||||
|
http-errors: 2.0.1
|
||||||
|
iconv-lite: 0.7.2
|
||||||
|
on-finished: 2.4.1
|
||||||
|
qs: 6.14.1
|
||||||
|
raw-body: 3.0.2
|
||||||
|
type-is: 2.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
boolbase@1.0.0: {}
|
boolbase@1.0.0: {}
|
||||||
|
|
||||||
bowser@2.13.1: {}
|
bowser@2.13.1: {}
|
||||||
@@ -10822,6 +11050,8 @@ snapshots:
|
|||||||
buildcheck@0.0.7:
|
buildcheck@0.0.7:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
bytes@3.1.2: {}
|
||||||
|
|
||||||
c12@3.1.0:
|
c12@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar: 4.0.3
|
chokidar: 4.0.3
|
||||||
@@ -11001,8 +11231,14 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
upper-case: 2.0.2
|
upper-case: 2.0.2
|
||||||
|
|
||||||
|
content-disposition@1.0.1: {}
|
||||||
|
|
||||||
|
content-type@1.0.5: {}
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
|
cookie-signature@1.2.2: {}
|
||||||
|
|
||||||
cookie@0.7.2: {}
|
cookie@0.7.2: {}
|
||||||
|
|
||||||
copy-anything@3.0.5:
|
copy-anything@3.0.5:
|
||||||
@@ -11152,6 +11388,8 @@ snapshots:
|
|||||||
|
|
||||||
defu@6.1.4: {}
|
defu@6.1.4: {}
|
||||||
|
|
||||||
|
depd@2.0.0: {}
|
||||||
|
|
||||||
destr@2.0.5: {}
|
destr@2.0.5: {}
|
||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
@@ -11251,6 +11489,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
ee-first@1.1.1: {}
|
||||||
|
|
||||||
effect@3.18.4:
|
effect@3.18.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.1.0
|
'@standard-schema/spec': 1.1.0
|
||||||
@@ -11284,6 +11524,8 @@ snapshots:
|
|||||||
highlight.js: 10.4.1
|
highlight.js: 10.4.1
|
||||||
lowlight: 1.17.0
|
lowlight: 1.17.0
|
||||||
|
|
||||||
|
encodeurl@2.0.0: {}
|
||||||
|
|
||||||
end-of-stream@1.4.5:
|
end-of-stream@1.4.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
@@ -11556,6 +11798,8 @@ snapshots:
|
|||||||
|
|
||||||
escalade@3.2.0: {}
|
escalade@3.2.0: {}
|
||||||
|
|
||||||
|
escape-html@1.0.3: {}
|
||||||
|
|
||||||
escape-string-regexp@4.0.0: {}
|
escape-string-regexp@4.0.0: {}
|
||||||
|
|
||||||
eslint-config-next@16.1.1(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
|
eslint-config-next@16.1.1(@typescript-eslint/parser@8.52.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
|
||||||
@@ -11774,12 +12018,47 @@ snapshots:
|
|||||||
|
|
||||||
esutils@2.0.3: {}
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
|
etag@1.8.1: {}
|
||||||
|
|
||||||
eventemitter3@4.0.7: {}
|
eventemitter3@4.0.7: {}
|
||||||
|
|
||||||
eventemitter3@5.0.1: {}
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
events@3.3.0: {}
|
events@3.3.0: {}
|
||||||
|
|
||||||
|
express@5.2.1:
|
||||||
|
dependencies:
|
||||||
|
accepts: 2.0.0
|
||||||
|
body-parser: 2.2.2
|
||||||
|
content-disposition: 1.0.1
|
||||||
|
content-type: 1.0.5
|
||||||
|
cookie: 0.7.2
|
||||||
|
cookie-signature: 1.2.2
|
||||||
|
debug: 4.4.3
|
||||||
|
depd: 2.0.0
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
etag: 1.8.1
|
||||||
|
finalhandler: 2.1.1
|
||||||
|
fresh: 2.0.0
|
||||||
|
http-errors: 2.0.1
|
||||||
|
merge-descriptors: 2.0.0
|
||||||
|
mime-types: 3.0.2
|
||||||
|
on-finished: 2.4.1
|
||||||
|
once: 1.4.0
|
||||||
|
parseurl: 1.3.3
|
||||||
|
proxy-addr: 2.0.7
|
||||||
|
qs: 6.14.1
|
||||||
|
range-parser: 1.2.1
|
||||||
|
router: 2.2.0
|
||||||
|
send: 1.2.1
|
||||||
|
serve-static: 2.2.1
|
||||||
|
statuses: 2.0.2
|
||||||
|
type-is: 2.0.1
|
||||||
|
vary: 1.1.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
exsolve@1.0.8: {}
|
exsolve@1.0.8: {}
|
||||||
|
|
||||||
extend@3.0.2: {}
|
extend@3.0.2: {}
|
||||||
@@ -11855,6 +12134,17 @@ snapshots:
|
|||||||
|
|
||||||
filter-obj@1.1.0: {}
|
filter-obj@1.1.0: {}
|
||||||
|
|
||||||
|
finalhandler@2.1.1:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
on-finished: 2.4.1
|
||||||
|
parseurl: 1.3.3
|
||||||
|
statuses: 2.0.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
locate-path: 6.0.0
|
locate-path: 6.0.0
|
||||||
@@ -11882,6 +12172,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fetch-blob: 3.2.0
|
fetch-blob: 3.2.0
|
||||||
|
|
||||||
|
forwarded@0.2.0: {}
|
||||||
|
|
||||||
fraction.js@4.3.7: {}
|
fraction.js@4.3.7: {}
|
||||||
|
|
||||||
framer-motion@12.23.22(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
framer-motion@12.23.22(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
|
||||||
@@ -11902,6 +12194,8 @@ snapshots:
|
|||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
|
|
||||||
|
fresh@2.0.0: {}
|
||||||
|
|
||||||
fs-constants@1.0.0: {}
|
fs-constants@1.0.0: {}
|
||||||
|
|
||||||
fs-extra@11.3.0:
|
fs-extra@11.3.0:
|
||||||
@@ -12123,6 +12417,14 @@ snapshots:
|
|||||||
domutils: 3.2.2
|
domutils: 3.2.2
|
||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
|
|
||||||
|
http-errors@2.0.1:
|
||||||
|
dependencies:
|
||||||
|
depd: 2.0.0
|
||||||
|
inherits: 2.0.4
|
||||||
|
setprototypeof: 1.2.0
|
||||||
|
statuses: 2.0.2
|
||||||
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
https-proxy-agent@5.0.0:
|
https-proxy-agent@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
@@ -12137,6 +12439,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
iconv-lite@0.7.2:
|
||||||
|
dependencies:
|
||||||
|
safer-buffer: 2.1.2
|
||||||
|
|
||||||
ieee754@1.2.1: {}
|
ieee754@1.2.1: {}
|
||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
@@ -12165,6 +12471,8 @@ snapshots:
|
|||||||
|
|
||||||
internmap@2.0.3: {}
|
internmap@2.0.3: {}
|
||||||
|
|
||||||
|
ipaddr.js@1.9.1: {}
|
||||||
|
|
||||||
ipaddr.js@2.3.0: {}
|
ipaddr.js@2.3.0: {}
|
||||||
|
|
||||||
is-arguments@1.2.0:
|
is-arguments@1.2.0:
|
||||||
@@ -12257,6 +12565,8 @@ snapshots:
|
|||||||
|
|
||||||
is-plain-object@5.0.0: {}
|
is-plain-object@5.0.0: {}
|
||||||
|
|
||||||
|
is-promise@4.0.0: {}
|
||||||
|
|
||||||
is-regex@1.2.1:
|
is-regex@1.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -12552,6 +12862,10 @@ snapshots:
|
|||||||
marked: 7.0.4
|
marked: 7.0.4
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
|
|
||||||
|
media-typer@1.1.0: {}
|
||||||
|
|
||||||
|
merge-descriptors@2.0.0: {}
|
||||||
|
|
||||||
merge-stream@2.0.0: {}
|
merge-stream@2.0.0: {}
|
||||||
|
|
||||||
merge2@1.4.1: {}
|
merge2@1.4.1: {}
|
||||||
@@ -12661,11 +12975,13 @@ snapshots:
|
|||||||
|
|
||||||
negotiator@0.6.3: {}
|
negotiator@0.6.3: {}
|
||||||
|
|
||||||
|
negotiator@1.0.0: {}
|
||||||
|
|
||||||
neo-async@2.6.2: {}
|
neo-async@2.6.2: {}
|
||||||
|
|
||||||
next-safe-action@7.10.8(next@16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76):
|
next-safe-action@7.10.8(next@16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod@3.25.76):
|
||||||
dependencies:
|
dependencies:
|
||||||
next: 16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
next: 16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -12699,7 +13015,7 @@ snapshots:
|
|||||||
- '@babel/core'
|
- '@babel/core'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
|
|
||||||
next@16.0.10(@babel/core@7.26.10)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
next@16.0.10(@babel/core@7.28.5)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@next/env': 16.0.10
|
'@next/env': 16.0.10
|
||||||
'@swc/helpers': 0.5.15
|
'@swc/helpers': 0.5.15
|
||||||
@@ -12707,7 +13023,7 @@ snapshots:
|
|||||||
postcss: 8.4.31
|
postcss: 8.4.31
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
react-dom: 19.2.3(react@19.2.3)
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.2.3)
|
styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@next/swc-darwin-arm64': 16.0.10
|
'@next/swc-darwin-arm64': 16.0.10
|
||||||
'@next/swc-darwin-x64': 16.0.10
|
'@next/swc-darwin-x64': 16.0.10
|
||||||
@@ -12830,6 +13146,10 @@ snapshots:
|
|||||||
|
|
||||||
ohash@2.0.11: {}
|
ohash@2.0.11: {}
|
||||||
|
|
||||||
|
on-finished@2.4.1:
|
||||||
|
dependencies:
|
||||||
|
ee-first: 1.1.1
|
||||||
|
|
||||||
once@1.4.0:
|
once@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
wrappy: 1.0.2
|
wrappy: 1.0.2
|
||||||
@@ -12907,6 +13227,8 @@ snapshots:
|
|||||||
leac: 0.6.0
|
leac: 0.6.0
|
||||||
peberminta: 0.9.0
|
peberminta: 0.9.0
|
||||||
|
|
||||||
|
parseurl@1.3.3: {}
|
||||||
|
|
||||||
pascal-case@3.1.2:
|
pascal-case@3.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
no-case: 3.0.4
|
no-case: 3.0.4
|
||||||
@@ -12935,6 +13257,8 @@ snapshots:
|
|||||||
lru-cache: 11.2.4
|
lru-cache: 11.2.4
|
||||||
minipass: 7.1.2
|
minipass: 7.1.2
|
||||||
|
|
||||||
|
path-to-regexp@8.3.0: {}
|
||||||
|
|
||||||
pathe@2.0.3: {}
|
pathe@2.0.3: {}
|
||||||
|
|
||||||
peberminta@0.9.0: {}
|
peberminta@0.9.0: {}
|
||||||
@@ -13106,6 +13430,11 @@ snapshots:
|
|||||||
'@types/node': 22.19.3
|
'@types/node': 22.19.3
|
||||||
long: 5.3.2
|
long: 5.3.2
|
||||||
|
|
||||||
|
proxy-addr@2.0.7:
|
||||||
|
dependencies:
|
||||||
|
forwarded: 0.2.0
|
||||||
|
ipaddr.js: 1.9.1
|
||||||
|
|
||||||
pump@3.0.3:
|
pump@3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
end-of-stream: 1.4.5
|
end-of-stream: 1.4.5
|
||||||
@@ -13134,6 +13463,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
|
range-parser@1.2.1: {}
|
||||||
|
|
||||||
|
raw-body@3.0.2:
|
||||||
|
dependencies:
|
||||||
|
bytes: 3.1.2
|
||||||
|
http-errors: 2.0.1
|
||||||
|
iconv-lite: 0.7.2
|
||||||
|
unpipe: 1.0.0
|
||||||
|
|
||||||
rc9@2.1.2:
|
rc9@2.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
defu: 6.1.4
|
defu: 6.1.4
|
||||||
@@ -13391,6 +13729,16 @@ snapshots:
|
|||||||
|
|
||||||
rou3@0.7.12: {}
|
rou3@0.7.12: {}
|
||||||
|
|
||||||
|
router@2.2.0:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
depd: 2.0.0
|
||||||
|
is-promise: 4.0.0
|
||||||
|
parseurl: 1.3.3
|
||||||
|
path-to-regexp: 8.3.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
run-parallel@1.2.0:
|
run-parallel@1.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask: 1.2.3
|
queue-microtask: 1.2.3
|
||||||
@@ -13441,6 +13789,22 @@ snapshots:
|
|||||||
|
|
||||||
semver@7.7.3: {}
|
semver@7.7.3: {}
|
||||||
|
|
||||||
|
send@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
etag: 1.8.1
|
||||||
|
fresh: 2.0.0
|
||||||
|
http-errors: 2.0.1
|
||||||
|
mime-types: 3.0.2
|
||||||
|
ms: 2.1.3
|
||||||
|
on-finished: 2.4.1
|
||||||
|
range-parser: 1.2.1
|
||||||
|
statuses: 2.0.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
sentence-case@3.0.4:
|
sentence-case@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
no-case: 3.0.4
|
no-case: 3.0.4
|
||||||
@@ -13451,6 +13815,15 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
randombytes: 2.1.0
|
randombytes: 2.1.0
|
||||||
|
|
||||||
|
serve-static@2.2.1:
|
||||||
|
dependencies:
|
||||||
|
encodeurl: 2.0.0
|
||||||
|
escape-html: 1.0.3
|
||||||
|
parseurl: 1.3.3
|
||||||
|
send: 1.2.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
set-cookie-parser@2.7.2: {}
|
set-cookie-parser@2.7.2: {}
|
||||||
|
|
||||||
set-function-length@1.2.2:
|
set-function-length@1.2.2:
|
||||||
@@ -13475,6 +13848,8 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
es-object-atoms: 1.1.1
|
es-object-atoms: 1.1.1
|
||||||
|
|
||||||
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
sharp@0.34.4:
|
sharp@0.34.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@img/colour': 1.0.0
|
'@img/colour': 1.0.0
|
||||||
@@ -13675,6 +14050,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
type-fest: 0.7.1
|
type-fest: 0.7.1
|
||||||
|
|
||||||
|
statuses@2.0.2: {}
|
||||||
|
|
||||||
stdin-discarder@0.2.2: {}
|
stdin-discarder@0.2.2: {}
|
||||||
|
|
||||||
stop-iteration-iterator@1.1.0:
|
stop-iteration-iterator@1.1.0:
|
||||||
@@ -13787,12 +14164,12 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@babel/core': 7.26.10
|
'@babel/core': 7.26.10
|
||||||
|
|
||||||
styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.2.3):
|
styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.2.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
client-only: 0.0.1
|
client-only: 0.0.1
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@babel/core': 7.26.10
|
'@babel/core': 7.28.5
|
||||||
|
|
||||||
sucrase@3.35.1:
|
sucrase@3.35.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -13880,14 +14257,14 @@ snapshots:
|
|||||||
ansi-escapes: 4.3.2
|
ansi-escapes: 4.3.2
|
||||||
supports-hyperlinks: 2.3.0
|
supports-hyperlinks: 2.3.0
|
||||||
|
|
||||||
terser-webpack-plugin@5.3.16(esbuild@0.25.10)(webpack@5.104.1(esbuild@0.27.2)):
|
terser-webpack-plugin@5.3.16(esbuild@0.25.10)(webpack@5.104.1(esbuild@0.25.10)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.31
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
jest-worker: 27.5.1
|
jest-worker: 27.5.1
|
||||||
schema-utils: 4.3.3
|
schema-utils: 4.3.3
|
||||||
serialize-javascript: 6.0.2
|
serialize-javascript: 6.0.2
|
||||||
terser: 5.44.1
|
terser: 5.44.1
|
||||||
webpack: 5.104.1(esbuild@0.25.10)
|
webpack: 5.104.1(esbuild@0.27.2)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
esbuild: 0.25.10
|
esbuild: 0.25.10
|
||||||
|
|
||||||
@@ -13925,6 +14302,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
|
toidentifier@1.0.1: {}
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
traverse@0.6.11:
|
traverse@0.6.11:
|
||||||
@@ -13985,6 +14364,12 @@ snapshots:
|
|||||||
|
|
||||||
type-fest@0.7.1: {}
|
type-fest@0.7.1: {}
|
||||||
|
|
||||||
|
type-is@2.0.1:
|
||||||
|
dependencies:
|
||||||
|
content-type: 1.0.5
|
||||||
|
media-typer: 1.1.0
|
||||||
|
mime-types: 3.0.2
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -14055,6 +14440,8 @@ snapshots:
|
|||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
unrs-resolver@1.11.1:
|
unrs-resolver@1.11.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
napi-postinstall: 0.3.4
|
napi-postinstall: 0.3.4
|
||||||
@@ -14242,7 +14629,7 @@ snapshots:
|
|||||||
|
|
||||||
webpack-sources@3.3.3: {}
|
webpack-sources@3.3.3: {}
|
||||||
|
|
||||||
webpack@5.104.1(esbuild@0.25.10):
|
webpack@5.104.1(esbuild@0.27.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint-scope': 3.7.7
|
'@types/eslint-scope': 3.7.7
|
||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
@@ -14266,7 +14653,7 @@ snapshots:
|
|||||||
neo-async: 2.6.2
|
neo-async: 2.6.2
|
||||||
schema-utils: 4.3.3
|
schema-utils: 4.3.3
|
||||||
tapable: 2.3.0
|
tapable: 2.3.0
|
||||||
terser-webpack-plugin: 5.3.16(esbuild@0.25.10)(webpack@5.104.1(esbuild@0.27.2))
|
terser-webpack-plugin: 5.3.16(esbuild@0.25.10)(webpack@5.104.1(esbuild@0.25.10))
|
||||||
watchpack: 2.5.0
|
watchpack: 2.5.0
|
||||||
webpack-sources: 3.3.3
|
webpack-sources: 3.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import next from "next";
|
||||||
|
import express from "express";
|
||||||
|
|
||||||
|
import router from "./src/features/api/router";
|
||||||
|
|
||||||
|
const port = Number(process.env.PORT) || 80;
|
||||||
|
|
||||||
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
|
const app = next({ dev, port: port, turbopack: true });
|
||||||
|
const handle = app.getRequestHandler();
|
||||||
|
|
||||||
|
app.prepare().then(() => {
|
||||||
|
const server = express();
|
||||||
|
|
||||||
|
server.use("/services/v1", router);
|
||||||
|
|
||||||
|
|
||||||
|
server.use((req, res, next) => {
|
||||||
|
if (req.path.startsWith('/services/v1')) return next();
|
||||||
|
handle(req, res).catch((err) => {
|
||||||
|
console.error('Next.js App Router error:', err);
|
||||||
|
res.status(500).send('Internal Server Error');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(`Next.js App Router running at http://localhost:${port}`);
|
||||||
|
console.log(`Express API running at http://localhost:${port}/express`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import express from "express";
|
||||||
|
import router from "../src/features/api/router";
|
||||||
|
|
||||||
|
export function mountApi(app: express.Express) {
|
||||||
|
app.use("/services/v1", router);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import next from "next";
|
||||||
|
import express from "express";
|
||||||
|
import {mountApi} from "./api";
|
||||||
|
|
||||||
|
const port = Number(process.env.PORT) || 8887;
|
||||||
|
const dev = process.env.NODE_ENV !== "production";
|
||||||
|
|
||||||
|
async function start() {
|
||||||
|
const nextApp = next({
|
||||||
|
dev,
|
||||||
|
port,
|
||||||
|
turbopack: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const handle = nextApp.getRequestHandler();
|
||||||
|
|
||||||
|
await nextApp.prepare();
|
||||||
|
|
||||||
|
const server = express();
|
||||||
|
|
||||||
|
mountApi(server);
|
||||||
|
|
||||||
|
server.use((req, res, next) => {
|
||||||
|
if (req.path.startsWith('/services/v1')) return next();
|
||||||
|
handle(req, res).catch((err) => {
|
||||||
|
console.error('Next.js App Router error:', err);
|
||||||
|
res.status(500).send('Internal Server Error');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(
|
||||||
|
`NEXT APP → http://localhost:${port}`
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`API → http://localhost:${port}/services/v1`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
start();
|
||||||
@@ -75,7 +75,7 @@ export const BackupActionsForm = ({backup, action}: BackupActionsFormProps) => {
|
|||||||
if (inner?.success) {
|
if (inner?.success) {
|
||||||
toast.success(inner.actionSuccess?.message);
|
toast.success(inner.actionSuccess?.message);
|
||||||
if (action === "download") {
|
if (action === "download") {
|
||||||
console.log(inner.value)
|
|
||||||
const url = inner.value
|
const url = inner.value
|
||||||
if (typeof url === "string") {
|
if (typeof url === "string") {
|
||||||
window.open(url, "_self");
|
window.open(url, "_self");
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export const downloadBackupAction = userAction.schema(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(input)
|
|
||||||
|
|
||||||
const result = await dispatchStorage(input, undefined, backupStorage.storageChannelId);
|
const result = await dispatchStorage(input, undefined, backupStorage.storageChannelId);
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
|||||||
@@ -106,8 +106,7 @@ export const ChannelPoliciesForm = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
console.log(policiesToUpdate);
|
|
||||||
console.log(policiesToAdd);
|
|
||||||
|
|
||||||
const promises = kind === "notification"
|
const promises = kind === "notification"
|
||||||
? [
|
? [
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import {Request, Response, NextFunction} from "express";
|
||||||
|
|
||||||
|
export function loggingMiddleware(req: Request, res: Response, next: NextFunction) {
|
||||||
|
console.log(`[API - SERVICES - V1] Received ${req.method} request : ${req.url} at ${new Date().toISOString()}`);
|
||||||
|
next();
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import express, {Router} from "express";
|
||||||
|
import uploadRouter from "./upload";
|
||||||
|
import {loggingMiddleware} from "@/features/api/middleware";
|
||||||
|
|
||||||
|
const router: Router = express.Router();
|
||||||
|
|
||||||
|
router.use(loggingMiddleware);
|
||||||
|
router.use("/upload", uploadRouter);
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import {Backup, DatabaseWith} from "@/db/schema/07_database";
|
||||||
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
|
import type {StorageInput, StorageResult} from "@/features/storages/types";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
|
import {eq} from "drizzle-orm";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import {PassThrough} from "stream";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import forge from "node-forge";
|
||||||
|
import crypto from "node:crypto";
|
||||||
|
import {pipeline} from "node:stream";
|
||||||
|
import { promisify } from "util";
|
||||||
|
|
||||||
|
|
||||||
|
export async function storeBackupFilesStream(
|
||||||
|
backup: Backup,
|
||||||
|
database: DatabaseWith,
|
||||||
|
fileStream: NodeJS.ReadableStream,
|
||||||
|
fileName: string
|
||||||
|
): Promise<StorageResult[]> {
|
||||||
|
|
||||||
|
const settings = await db.query.setting.findFirst({
|
||||||
|
where: eq(drizzleDb.schemas.setting.name, "system"),
|
||||||
|
with: {storageChannel: true},
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultPolicy = settings?.storageChannel
|
||||||
|
? [{
|
||||||
|
id: null,
|
||||||
|
storageChannelId: settings.storageChannel.id,
|
||||||
|
enabled: settings.storageChannel.enabled,
|
||||||
|
}]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const enabledPolicies = database.storagePolicies?.filter(p => p.enabled) ?? [];
|
||||||
|
const policies = enabledPolicies.length ? enabledPolicies : defaultPolicy;
|
||||||
|
|
||||||
|
if (!policies.length) {
|
||||||
|
await db.update(drizzleDb.schemas.backup)
|
||||||
|
.set(withUpdatedAt({status: "failed"}))
|
||||||
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const storagePath = `backups/${database.project?.slug}/${fileName}`;
|
||||||
|
// const teeStreams = teeStreamSafe(fileStream, policies.length);
|
||||||
|
const teeStreams = teeStream(fileStream, policies.length);
|
||||||
|
|
||||||
|
|
||||||
|
const results = await Promise.all(
|
||||||
|
policies.map(async (policy, index) => {
|
||||||
|
const pass = teeStreams[index];
|
||||||
|
console.log("policy", index, policy.id)
|
||||||
|
const [backupStorage] = await db
|
||||||
|
.insert(drizzleDb.schemas.backupStorage)
|
||||||
|
.values({
|
||||||
|
backupId: backup.id,
|
||||||
|
storageChannelId: policy.storageChannelId,
|
||||||
|
status: "pending",
|
||||||
|
path: storagePath,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
const input: StorageInput = {
|
||||||
|
action: "upload",
|
||||||
|
data: {
|
||||||
|
path: storagePath,
|
||||||
|
file: teeStreams[index],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let result: StorageResult;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = policy.id
|
||||||
|
? await dispatchStorage(input, policy.id)
|
||||||
|
: await dispatchStorage(input, undefined, policy.storageChannelId);
|
||||||
|
} catch (err: any) {
|
||||||
|
pass.destroy(err);
|
||||||
|
result = {success: false, provider: null, error: err.message};
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.update(drizzleDb.schemas.backupStorage)
|
||||||
|
.set(withUpdatedAt({status: result.success ? "success" : "failed"}))
|
||||||
|
.where(eq(drizzleDb.schemas.backupStorage.id, backupStorage.id));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
console.log("result upload", results);
|
||||||
|
|
||||||
|
const backupStatus = results.some(r => r.success) ? "success" : "failed";
|
||||||
|
|
||||||
|
await db.update(drizzleDb.schemas.backup)
|
||||||
|
.set(withUpdatedAt({status: backupStatus}))
|
||||||
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function createDecryptionStream(
|
||||||
|
encryptedAesKeyHex: string,
|
||||||
|
ivHex: string
|
||||||
|
) {
|
||||||
|
const privateKeyPem = fs.readFileSync(
|
||||||
|
"private/keys/server_private.pem",
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
|
||||||
|
const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);
|
||||||
|
|
||||||
|
const encryptedBytes = forge.util.hexToBytes(encryptedAesKeyHex);
|
||||||
|
const aesKeyBytes = privateKey.decrypt(encryptedBytes, "RSA-OAEP", {
|
||||||
|
md: forge.md.sha256.create(),
|
||||||
|
mgf1: {md: forge.md.sha256.create()},
|
||||||
|
});
|
||||||
|
|
||||||
|
const aesKey = Buffer.from(aesKeyBytes, "binary");
|
||||||
|
const iv = Buffer.from(ivHex, "hex");
|
||||||
|
|
||||||
|
return crypto.createDecipheriv("aes-256-cbc", aesKey, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getFileExtension(dbType: string) {
|
||||||
|
switch (dbType) {
|
||||||
|
case "postgresql":
|
||||||
|
return ".dump";
|
||||||
|
case "mysql":
|
||||||
|
return ".sql";
|
||||||
|
default:
|
||||||
|
return ".dump";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipelinePromise = promisify(pipeline);
|
||||||
|
|
||||||
|
function teeStream(stream: NodeJS.ReadableStream, n: number): PassThrough[] {
|
||||||
|
const taps = Array.from({ length: n }, () => new PassThrough());
|
||||||
|
taps.forEach(tap => pipelinePromise(stream, tap).catch(err => tap.destroy(err)));
|
||||||
|
return taps;
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import {Backup, DatabaseWith} from "@/db/schema/07_database";
|
||||||
|
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||||
|
import type {StorageInput, StorageResult} from "@/features/storages/types";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {eq} from "drizzle-orm";
|
||||||
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
|
import {saveStreamToTempFile} from "@/features/api/upload/helpers/file";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save stream to a temporary file and upload to all storage providers in parallel.
|
||||||
|
*/
|
||||||
|
export default async function uploadTempFileToProviders(
|
||||||
|
backup: Backup,
|
||||||
|
database: DatabaseWith,
|
||||||
|
inputStream: NodeJS.ReadableStream,
|
||||||
|
fileName: string
|
||||||
|
): Promise<StorageResult[]> {
|
||||||
|
|
||||||
|
const tmpPath = await saveStreamToTempFile(inputStream, fileName);
|
||||||
|
|
||||||
|
const stats = fs.statSync(tmpPath);
|
||||||
|
const fileSize = stats.size;
|
||||||
|
console.log(tmpPath);
|
||||||
|
|
||||||
|
const settings = await db.query.setting.findFirst({
|
||||||
|
where: eq(drizzleDb.schemas.setting.name, "system"),
|
||||||
|
with: {storageChannel: true},
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultPolicy = settings?.storageChannel
|
||||||
|
? [{
|
||||||
|
id: null,
|
||||||
|
storageChannelId: settings.storageChannel.id,
|
||||||
|
enabled: settings.storageChannel.enabled,
|
||||||
|
}]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const enabledPolicies = database.storagePolicies?.filter(p => p.enabled) ?? [];
|
||||||
|
const policies = enabledPolicies.length ? enabledPolicies : defaultPolicy;
|
||||||
|
|
||||||
|
if (!policies.length) {
|
||||||
|
await db.update(drizzleDb.schemas.backup)
|
||||||
|
.set(withUpdatedAt({status: "failed"}))
|
||||||
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
fs.existsSync(tmpPath) && fs.unlinkSync(tmpPath);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const storagePath = `backups/${database.project?.slug}/${fileName}`;
|
||||||
|
|
||||||
|
const results = await Promise.all(
|
||||||
|
policies.map(async (policy) => {
|
||||||
|
const fileStream = fs.createReadStream(tmpPath);
|
||||||
|
|
||||||
|
const [backupStorage] = await db.insert(drizzleDb.schemas.backupStorage)
|
||||||
|
.values({
|
||||||
|
backupId: backup.id,
|
||||||
|
storageChannelId: policy.storageChannelId,
|
||||||
|
status: "pending",
|
||||||
|
path: storagePath,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
const input: StorageInput = {
|
||||||
|
action: "upload",
|
||||||
|
data: {path: storagePath, file: fileStream, size: fileSize},
|
||||||
|
};
|
||||||
|
|
||||||
|
let result: StorageResult;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = policy.id
|
||||||
|
? await dispatchStorage(input, policy.id)
|
||||||
|
: await dispatchStorage(input, undefined, policy.storageChannelId);
|
||||||
|
} catch (err: any) {
|
||||||
|
result = {success: false, provider: null, error: err.message};
|
||||||
|
}
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
await db.update(drizzleDb.schemas.backupStorage)
|
||||||
|
.set(withUpdatedAt({status: result.success ? "success" : "failed"}))
|
||||||
|
.where(eq(drizzleDb.schemas.backupStorage.id, backupStorage.id));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const backupStatus = results.some(r => r.success) ? "success" : "failed";
|
||||||
|
await db.update(drizzleDb.schemas.backup)
|
||||||
|
.set(withUpdatedAt({
|
||||||
|
fileSize: fileSize,
|
||||||
|
status: backupStatus
|
||||||
|
}))
|
||||||
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
|
||||||
|
fs.existsSync(tmpPath) && fs.unlinkSync(tmpPath);
|
||||||
|
|
||||||
|
console.log(results);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import {promisify} from "util";
|
||||||
|
import {pipeline} from "stream";
|
||||||
|
|
||||||
|
const pipelineAsync = promisify(pipeline);
|
||||||
|
const TMP_DIR = path.join(process.cwd(), "private/uploads/tmp");
|
||||||
|
fs.mkdirSync(TMP_DIR, { recursive: true });
|
||||||
|
|
||||||
|
export async function saveStreamToTempFile(stream: NodeJS.ReadableStream, fileName: string): Promise<string> {
|
||||||
|
const tmpPath = path.join(TMP_DIR, fileName);
|
||||||
|
const writeStream = fs.createWriteStream(tmpPath);
|
||||||
|
await pipelineAsync(stream, writeStream);
|
||||||
|
return tmpPath;
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
import express, {Request, Response, Router} from "express";
|
||||||
|
import {v4 as uuidv4} from "uuid";
|
||||||
|
import {and, eq} from "drizzle-orm";
|
||||||
|
import * as drizzleDb from "@/db";
|
||||||
|
import {db} from "@/db";
|
||||||
|
import {createDecryptionStream, getFileExtension} from "./helpers";
|
||||||
|
import {isUuidv4} from "@/utils/verify-uuid";
|
||||||
|
import uploadTempFileToProviders from "@/features/api/upload/helpers/common";
|
||||||
|
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||||
|
import {Backup} from "@/db/schema/07_database";
|
||||||
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
|
||||||
|
const router: Router = express.Router();
|
||||||
|
|
||||||
|
router.post("/:agentId", async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
const agentId = req.params.agentId as string | undefined;
|
||||||
|
const generatedId = req.headers["x-generated-id"] as string | undefined;
|
||||||
|
const status = req.headers["x-status"] as string | undefined;
|
||||||
|
const encryptedAesKeyHex = req.headers["x-aes-key"] as string | undefined;
|
||||||
|
const ivHex = req.headers["x-iv"] as string | undefined;
|
||||||
|
const method = (req.headers["x-method"] as string) ?? "manual";
|
||||||
|
const extension = req.headers["x-extension"] as string | undefined;
|
||||||
|
|
||||||
|
|
||||||
|
if (!generatedId || !encryptedAesKeyHex || !ivHex || !agentId || !status) {
|
||||||
|
return res.status(400).json({error: "Missing required headers/params"});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isUuidv4(generatedId)) {
|
||||||
|
return res.status(400).json({error: "generatedId is not a valid UUID"});
|
||||||
|
}
|
||||||
|
|
||||||
|
const agent = await db.query.agent.findFirst({
|
||||||
|
where: eq(drizzleDb.schemas.agent.id, agentId),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!agent) {
|
||||||
|
return res.status(404).json({error: "Agent not found"});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const database = await db.query.database.findFirst({
|
||||||
|
where: eq(drizzleDb.schemas.database.agentDatabaseId, generatedId),
|
||||||
|
with: {
|
||||||
|
project: true,
|
||||||
|
storagePolicies: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!database) {
|
||||||
|
return res.status(404).json({error: "Database not found"});
|
||||||
|
}
|
||||||
|
|
||||||
|
let backup: Backup | null | undefined = null;
|
||||||
|
|
||||||
|
if (method === "automatic") {
|
||||||
|
[backup] = await db
|
||||||
|
.insert(drizzleDb.schemas.backup)
|
||||||
|
.values({
|
||||||
|
status: "ongoing",
|
||||||
|
databaseId: database.id,
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
} else {
|
||||||
|
backup = await db.query.backup.findFirst({
|
||||||
|
where: and(
|
||||||
|
eq(drizzleDb.schemas.backup.databaseId, database.id),
|
||||||
|
eq(drizzleDb.schemas.backup.status, "ongoing")
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backup) {
|
||||||
|
return res.status(404).json({error: "Backup not found"});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (status === "success") {
|
||||||
|
|
||||||
|
const decipher = createDecryptionStream(encryptedAesKeyHex, ivHex);
|
||||||
|
|
||||||
|
const fileExt = extension || getFileExtension(database.dbms);
|
||||||
|
const fileName = `${uuidv4()}${fileExt}`;
|
||||||
|
|
||||||
|
const decryptedStream = req.pipe(decipher);
|
||||||
|
|
||||||
|
await uploadTempFileToProviders(backup, database, decryptedStream, fileName);
|
||||||
|
await sendNotificationsBackupRestore(database, "success_backup");
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
|
return res.json({success: true});
|
||||||
|
} else {
|
||||||
|
await db
|
||||||
|
.update(drizzleDb.schemas.backup)
|
||||||
|
.set(withUpdatedAt({status: 'failed'}))
|
||||||
|
.where(eq(drizzleDb.schemas.backup.id, backup.id));
|
||||||
|
|
||||||
|
eventEmitter.emit('modification', {update: true});
|
||||||
|
|
||||||
|
await sendNotificationsBackupRestore(database, "error_backup");
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
error: "Backup successfully updated with status failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Upload error:", err);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: "Upload failed",
|
||||||
|
detail: err.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default router;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
|
export const eventEmitter = new EventEmitter();
|
||||||
@@ -24,18 +24,27 @@ export async function uploadGoogleDrive(
|
|||||||
? await ensureFolderPath(client, folderPath, config.folderId)
|
? await ensureFolderPath(client, folderPath, config.folderId)
|
||||||
: config.folderId;
|
: config.folderId;
|
||||||
|
|
||||||
|
|
||||||
const existing = await findFileByName(client, fileName, folderId);
|
const existing = await findFileByName(client, fileName, folderId);
|
||||||
if (existing) return {success: false, provider: "google-drive", error: "File already exists"};
|
if (existing) return {success: false, provider: "google-drive", error: "File already exists"};
|
||||||
|
|
||||||
|
let fileStream: Readable;
|
||||||
|
const file = input.data.file;
|
||||||
|
if (Buffer.isBuffer(file) || file instanceof Uint8Array) {
|
||||||
|
fileStream = Readable.from(file);
|
||||||
|
} else if ((file as any).pipe) {
|
||||||
|
fileStream = file as Readable;
|
||||||
|
} else {
|
||||||
|
throw new Error("Unsupported file type for streaming upload");
|
||||||
|
}
|
||||||
|
|
||||||
await client.files.create({
|
await client.files.create({
|
||||||
requestBody: {name: fileName, parents: [folderId]},
|
requestBody: {name: fileName, parents: [folderId]},
|
||||||
media: {body: Readable.from(input.data.file as Buffer)},
|
media: {body: fileStream},
|
||||||
fields: "id",
|
fields: "id",
|
||||||
supportsAllDrives: true,
|
supportsAllDrives: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (input.data.url) {
|
if (input.data.url) {
|
||||||
const url = await generateFileUrl(input);
|
const url = await generateFileUrl(input);
|
||||||
if (!url) {
|
if (!url) {
|
||||||
@@ -68,11 +77,15 @@ export async function getGoogleDrive(
|
|||||||
const fileId = await resolveFilePath(client, input.data.path, config.folderId);
|
const fileId = await resolveFilePath(client, input.data.path, config.folderId);
|
||||||
if (!fileId) return {success: false, provider: "google-drive", error: "File not found"};
|
if (!fileId) return {success: false, provider: "google-drive", error: "File not found"};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const res = await client.files.get(
|
const res = await client.files.get(
|
||||||
{fileId, alt: "media", supportsAllDrives: true},
|
{fileId, alt: "media", supportsAllDrives: true},
|
||||||
{responseType: "arraybuffer"}
|
{responseType: "stream"}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const stream = res.data as Readable;
|
||||||
|
|
||||||
|
|
||||||
if (input.data.signedUrl) {
|
if (input.data.signedUrl) {
|
||||||
const url = await generateFileUrl(input);
|
const url = await generateFileUrl(input);
|
||||||
@@ -88,7 +101,7 @@ export async function getGoogleDrive(
|
|||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
provider: "google-drive",
|
provider: "google-drive",
|
||||||
file: Buffer.from(res.data as ArrayBuffer),
|
file: stream,
|
||||||
url: url,
|
url: url,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -96,7 +109,7 @@ export async function getGoogleDrive(
|
|||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
provider: "google-drive",
|
provider: "google-drive",
|
||||||
file: Buffer.from(res.data as ArrayBuffer),
|
file: stream,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
// export type GoogleDriveConfig = {
|
|
||||||
// clientEmail: string;
|
|
||||||
// privateKey: string;
|
|
||||||
// folderId: string;
|
|
||||||
// };
|
|
||||||
|
|
||||||
|
|
||||||
export type GoogleDriveConfig = {
|
export type GoogleDriveConfig = {
|
||||||
clientId: string;
|
clientId: string;
|
||||||
|
|||||||
@@ -1,95 +1,109 @@
|
|||||||
"use server"
|
"use server"
|
||||||
import {mkdir, writeFile, unlink, readFile} from 'fs/promises';
|
import {mkdir, unlink} from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {StorageDeleteInput, StorageGetInput, StorageMetaData, StorageResult, StorageUploadInput} from '../types';
|
import {StorageDeleteInput, StorageGetInput, StorageMetaData, StorageResult, StorageUploadInput} from '../types';
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import {getServerUrl} from "@/utils/get-server-url";
|
|
||||||
import {generateFileUrl} from "@/features/storages/helpers";
|
import {generateFileUrl} from "@/features/storages/helpers";
|
||||||
|
import {Readable} from "node:stream";
|
||||||
|
|
||||||
const BASE_DIR = "/private/uploads/";
|
const BASE_DIR = "/private/uploads/";
|
||||||
|
|
||||||
export async function uploadLocal(
|
export async function uploadLocal(
|
||||||
config: { baseDir?: string },
|
config: { baseDir?: string },
|
||||||
input: { data: StorageUploadInput, metadata?: StorageMetaData }
|
input: { data: StorageUploadInput; metadata?: StorageMetaData }
|
||||||
): Promise<StorageResult> {
|
): Promise<StorageResult> {
|
||||||
const base = config.baseDir || BASE_DIR;
|
const base = config.baseDir || BASE_DIR;
|
||||||
const fullPath = path.join(process.cwd(), base, input.data.path);
|
const fullPath = path.join(process.cwd(), base, input.data.path);
|
||||||
|
|
||||||
const dir = path.dirname(fullPath);
|
const dir = path.dirname(fullPath);
|
||||||
|
|
||||||
await mkdir(dir, {recursive: true});
|
await mkdir(dir, { recursive: true });
|
||||||
await writeFile(fullPath, input.data.file);
|
|
||||||
|
|
||||||
|
try {
|
||||||
if (input.data.url) {
|
const file = input.data.file;
|
||||||
const url = await generateFileUrl(input);
|
if (Buffer.isBuffer(file)) {
|
||||||
if (!url) {
|
await fs.promises.writeFile(fullPath, input.data.file);
|
||||||
return {
|
} else if (file instanceof Readable) {
|
||||||
success: false,
|
await new Promise<void>((resolve, reject) => {
|
||||||
provider: "local",
|
const writable = fs.createWriteStream(fullPath);
|
||||||
response: "Unable to get url file"
|
file.pipe(writable);
|
||||||
};
|
writable.on("finish", resolve);
|
||||||
|
writable.on("error", reject);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return { success: false, provider: "local", error: "Unsupported file type. Must be Buffer or ReadableStream" };
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
success: true,
|
if (input.data.url) {
|
||||||
provider: 'local',
|
const url = await generateFileUrl(input);
|
||||||
url: url
|
if (!url) {
|
||||||
};
|
return { success: false, provider: "local", response: "Unable to get URL" };
|
||||||
|
}
|
||||||
|
return { success: true, provider: "local", url };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true, provider: "local" };
|
||||||
|
} catch (err: any) {
|
||||||
|
try { await unlink(fullPath); } catch {}
|
||||||
|
return { success: false, provider: "local", error: err.message || "Upload failed" };
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
provider: 'local',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLocal(
|
export async function getLocal(
|
||||||
config: { baseDir?: string },
|
config: { baseDir?: string },
|
||||||
input: { data: StorageGetInput, metadata: StorageMetaData }
|
input: { data: StorageGetInput; metadata: StorageMetaData }
|
||||||
): Promise<StorageResult> {
|
): Promise<StorageResult> {
|
||||||
const base = config.baseDir || BASE_DIR;
|
const base = config.baseDir || BASE_DIR;
|
||||||
const filePath = path.join(process.cwd(), base, input.data.path)
|
const filePath = path.join(process.cwd(), base, input.data.path);
|
||||||
const fileName = path.basename(input.data.path);
|
|
||||||
|
|
||||||
const file = await readFile(filePath);
|
|
||||||
|
|
||||||
if (!fs.existsSync(filePath)) {
|
if (!fs.existsSync(filePath)) {
|
||||||
console.error("File not found at:", filePath);
|
console.error("File not found at:", filePath);
|
||||||
return ({
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
provider: 'local',
|
provider: "local",
|
||||||
});
|
error: "File not found",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileStream: fs.ReadStream | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fileStream = fs.createReadStream(filePath);
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error("Error creating read stream:", err);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
provider: "local",
|
||||||
|
error: err.message,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.data.signedUrl) {
|
if (input.data.signedUrl) {
|
||||||
const url = await generateFileUrl(input);
|
const url = await generateFileUrl(input);
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
provider: "local",
|
provider: "local",
|
||||||
response: "Unable to get url file"
|
error: "Unable to generate signed URL",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
provider: "local",
|
provider: "local",
|
||||||
file: file,
|
file: fileStream,
|
||||||
url: url,
|
url,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
provider: "local",
|
provider: "local",
|
||||||
file: file,
|
file: fileStream,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function deleteLocal(
|
export async function deleteLocal(
|
||||||
config: { baseDir?: string },
|
config: { baseDir?: string },
|
||||||
input: { data: StorageDeleteInput, metadata?: StorageMetaData }
|
input: { data: StorageDeleteInput, metadata?: StorageMetaData }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as Minio from "minio";
|
import * as Minio from "minio";
|
||||||
import {StorageDeleteInput, StorageGetInput, StorageMetaData, StorageResult, StorageUploadInput} from "../types";
|
import {StorageDeleteInput, StorageGetInput, StorageMetaData, StorageResult, StorageUploadInput} from "../types";
|
||||||
import {generateFileUrl} from "@/features/storages/helpers";
|
import {Readable} from "node:stream";
|
||||||
|
|
||||||
type S3Config = {
|
type S3Config = {
|
||||||
endPointUrl: string;
|
endPointUrl: string;
|
||||||
@@ -32,72 +32,70 @@ async function ensureBucket(config: S3Config) {
|
|||||||
|
|
||||||
export async function uploadS3(
|
export async function uploadS3(
|
||||||
config: S3Config,
|
config: S3Config,
|
||||||
input: { data: StorageUploadInput, metadata?: StorageMetaData }
|
input: { data: StorageUploadInput, metadata?: StorageMetaData }
|
||||||
): Promise<StorageResult> {
|
): Promise<StorageResult> {
|
||||||
const client = await getS3Client(config);
|
const client = await getS3Client(config);
|
||||||
|
console.log(client);
|
||||||
await ensureBucket(config);
|
await ensureBucket(config);
|
||||||
|
|
||||||
const key = `${BASE_DIR}${input.data.path}`;
|
const key = `${BASE_DIR}${input.data.path}`;
|
||||||
|
const file = input.data.file;
|
||||||
|
|
||||||
|
console.log(key)
|
||||||
|
|
||||||
|
let uploadStream: Readable;
|
||||||
|
if (Buffer.isBuffer(file) || file instanceof Uint8Array) {
|
||||||
|
uploadStream = Readable.from(file);
|
||||||
|
} else if ((file as any).pipe) {
|
||||||
|
uploadStream = file;
|
||||||
|
} else {
|
||||||
|
throw new Error("Unsupported file type for streaming upload");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.statObject(config.bucketName, key);
|
const result = await client.putObject(config.bucketName, key, uploadStream, input.data.size);
|
||||||
return {success: false, provider: "s3", error: "File already exists"};
|
console.log(result);
|
||||||
} catch {
|
} catch (err: any) {
|
||||||
// continue if not found
|
return {success: false, provider: "s3", error: err.message};
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.putObject(config.bucketName, key, input.data.file as Buffer);
|
return {success: true, provider: "s3"};
|
||||||
|
|
||||||
|
|
||||||
if (input.data.url) {
|
|
||||||
const url = await generateFileUrl(input);
|
|
||||||
if (!url) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
provider: "s3",
|
|
||||||
response: "Unable to get url file"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
provider: 's3',
|
|
||||||
url: url
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
provider: 's3',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getS3(config: S3Config, input: { data: StorageGetInput, metadata: StorageMetaData }): Promise<StorageResult> {
|
|
||||||
const client = await getS3Client(config);
|
|
||||||
|
|
||||||
|
export async function getS3(
|
||||||
|
config: S3Config,
|
||||||
|
input: { data: StorageGetInput, metadata: StorageMetaData }
|
||||||
|
): Promise<StorageResult> {
|
||||||
|
const client = await getS3Client(config);
|
||||||
const key = `${BASE_DIR}${input.data.path}`;
|
const key = `${BASE_DIR}${input.data.path}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.statObject(config.bucketName, key);
|
await client.statObject(config.bucketName, key);
|
||||||
} catch {
|
} catch {
|
||||||
return {success: false, provider: "s3", error: "File not found"};
|
return {success: false, provider: "s3", error: "File not found"};
|
||||||
}
|
}
|
||||||
|
|
||||||
const presignedUrl = await client.presignedGetObject(config.bucketName, key, 60);
|
|
||||||
|
|
||||||
const fileStream = await client.getObject(config.bucketName, key);
|
const fileStream = await client.getObject(config.bucketName, key);
|
||||||
const chunks: Buffer[] = [];
|
|
||||||
for await (const chunk of fileStream) chunks.push(chunk as Buffer);
|
let presignedUrl: string | undefined;
|
||||||
const buffer = Buffer.concat(chunks);
|
if (input.data.signedUrl) {
|
||||||
|
presignedUrl = await client.presignedGetObject(config.bucketName, key, input.data.expiresInSeconds ?? 60);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
provider: "s3",
|
provider: "s3",
|
||||||
file: buffer,
|
file: fileStream as unknown as Buffer | Readable,
|
||||||
url: presignedUrl,
|
url: presignedUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteS3(config: S3Config, input: { data: StorageDeleteInput, metadata?: StorageMetaData }): Promise<StorageResult> {
|
|
||||||
|
export async function deleteS3(config: S3Config, input: {
|
||||||
|
data: StorageDeleteInput,
|
||||||
|
metadata?: StorageMetaData
|
||||||
|
}): Promise<StorageResult> {
|
||||||
const client = await getS3Client(config);
|
const client = await getS3Client(config);
|
||||||
const key = `${BASE_DIR}${input.data.path}`;
|
const key = `${BASE_DIR}${input.data.path}`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import {Readable} from "node:stream";
|
||||||
|
|
||||||
export type StorageProviderKind =
|
export type StorageProviderKind =
|
||||||
| 'local'
|
| 'local'
|
||||||
| 's3'
|
| 's3'
|
||||||
@@ -20,9 +22,10 @@ export type StorageMetaData = {
|
|||||||
|
|
||||||
export interface StorageUploadInput {
|
export interface StorageUploadInput {
|
||||||
path: string;
|
path: string;
|
||||||
file: Buffer | Uint8Array;
|
file: Readable | Buffer | Uint8Array;
|
||||||
url?: boolean;
|
url?: boolean;
|
||||||
contentType?: string;
|
contentType?: string;
|
||||||
|
size?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StorageGetInput {
|
export interface StorageGetInput {
|
||||||
@@ -37,7 +40,7 @@ export interface StorageDeleteInput {
|
|||||||
|
|
||||||
export type StorageInput =
|
export type StorageInput =
|
||||||
| { action: 'upload'; data: StorageUploadInput, metadata?: StorageMetaData }
|
| { action: 'upload'; data: StorageUploadInput, metadata?: StorageMetaData }
|
||||||
| { action: 'get'; data: StorageGetInput, metadata: StorageMetaData}
|
| { action: 'get'; data: StorageGetInput, metadata: StorageMetaData }
|
||||||
| { action: 'delete'; data: StorageDeleteInput, metadata?: StorageMetaData }
|
| { action: 'delete'; data: StorageDeleteInput, metadata?: StorageMetaData }
|
||||||
| { action: 'ping'; };
|
| { action: 'ping'; };
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ export interface StorageResult {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
provider: StorageProviderKind | null;
|
provider: StorageProviderKind | null;
|
||||||
url?: string;
|
url?: string;
|
||||||
file?: Buffer;
|
file?: Buffer | Readable;
|
||||||
error?: string;
|
error?: string;
|
||||||
response?: any;
|
response?: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -517,7 +517,6 @@ export const getActiveMember = async () => {
|
|||||||
const member = await auth.api.getActiveMember({
|
const member = await auth.api.getActiveMember({
|
||||||
headers: await headers(),
|
headers: await headers(),
|
||||||
});
|
});
|
||||||
console.log(member);
|
|
||||||
|
|
||||||
return member as MemberWithUser;
|
return member as MemberWithUser;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import nodemailer from "nodemailer";
|
import nodemailer from "nodemailer";
|
||||||
|
import {Server} from "./types"
|
||||||
|
|
||||||
export const createTransporter = (server: Server) => {
|
export const createTransporter = (server: Server) => {
|
||||||
const portNumber = Number(server.port);
|
const portNumber = Number(server.port);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {db} from "@/db";
|
|||||||
import {eq} from "drizzle-orm";
|
import {eq} from "drizzle-orm";
|
||||||
import * as drizzleDb from "@/db";
|
import * as drizzleDb from "@/db";
|
||||||
import {createTransporter} from "@/lib/email/helpers";
|
import {createTransporter} from "@/lib/email/helpers";
|
||||||
|
import {Payload} from "@/lib/email/types";
|
||||||
|
|
||||||
export const sendEmail = async (data: Payload) => {
|
export const sendEmail = async (data: Payload) => {
|
||||||
const settings = await db
|
const settings = await db
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
|
|
||||||
type Payload = {
|
export type Payload = {
|
||||||
to: string;
|
to: string;
|
||||||
from?: string;
|
from?: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
html: any;
|
html: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Server = {
|
export type Server = {
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
user: string;
|
user: string;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ 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 {eventEmitter} from "../../../../app/api/events/route";
|
import {eventEmitter} from "@/features/shared/event";
|
||||||
|
|
||||||
|
|
||||||
export const retentionCleanTask = async () => {
|
export const retentionCleanTask = async () => {
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ async function getS3Client() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const baseConfig = {
|
const baseConfig = {
|
||||||
endPoint: settings.s3EndPointUrl ?? "",
|
endPoint: settings?.s3EndPointUrl ?? "",
|
||||||
accessKey: settings.s3AccessKeyId ?? "",
|
accessKey: settings?.s3AccessKeyId ?? "",
|
||||||
secretKey: settings.s3SecretAccessKey ?? "",
|
secretKey: settings?.s3SecretAccessKey ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Minio.Client({
|
return new Minio.Client({
|
||||||
|
|||||||
Reference in New Issue
Block a user