feat(admin): add streaming upload heapsnapshot endpoint

This commit is contained in:
Eric Allam
2026-01-27 23:51:22 +00:00
parent eeab6bdeac
commit ce8e63067c
4 changed files with 396 additions and 31 deletions
+118 -25
View File
@@ -1,11 +1,15 @@
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { type DataFunctionArgs } from "@remix-run/node";
import fs from "fs";
import os from "os";
import path from "path";
import { PassThrough } from "stream";
import v8 from "v8";
import { prisma } from "~/db.server";
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
import { logger } from "~/services/logger.server";
// Use 100MB parts for faster parallel uploads of large snapshots
const PART_SIZE = 100 * 1024 * 1024;
// Use high parallelism to maximize upload speed
const QUEUE_SIZE = 8;
// Format date as yyyy-MM-dd HH_mm_ss_SSS
function formatDate(date: Date) {
@@ -24,6 +28,32 @@ function formatDate(date: Date) {
.padStart(2, "0")}_${milliseconds.toString().padStart(3, "0")}`;
}
function getS3Config() {
const bucket = process.env.SNAPSHOT_S3_BUCKET;
const region = process.env.SNAPSHOT_S3_REGION ?? "us-east-1";
if (!bucket) {
return undefined;
}
// Optional - only needed for non-AWS S3 (MinIO, R2, etc.) or local dev
const endpoint = process.env.SNAPSHOT_S3_ENDPOINT;
const accessKeyId = process.env.SNAPSHOT_S3_ACCESS_KEY_ID;
const secretAccessKey = process.env.SNAPSHOT_S3_SECRET_ACCESS_KEY;
// If explicit credentials provided, use them (local dev / non-AWS)
// Otherwise, SDK uses default credential chain (IAM role, env vars, etc.)
const credentials =
accessKeyId && secretAccessKey ? { accessKeyId, secretAccessKey } : undefined;
return {
bucket,
region,
endpoint,
credentials,
};
}
export async function loader({ request }: DataFunctionArgs) {
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
@@ -41,31 +71,94 @@ export async function loader({ request }: DataFunctionArgs) {
throw new Response("You must be an admin to perform this action", { status: 403 });
}
const tempDir = os.tmpdir();
const filepath = path.join(
tempDir,
`${getTaskIdentifier()}-${formatDate(new Date())}.heapsnapshot`
);
const s3Config = getS3Config();
const snapshotPath = v8.writeHeapSnapshot(filepath);
if (!snapshotPath) {
throw new Response("No snapshot saved", { status: 500 });
if (!s3Config) {
throw new Response(
"S3 is not configured. Set SNAPSHOT_S3_ENDPOINT, SNAPSHOT_S3_BUCKET, SNAPSHOT_S3_ACCESS_KEY_ID, and SNAPSHOT_S3_SECRET_ACCESS_KEY.",
{ status: 500 }
);
}
const body = new PassThrough();
const stream = fs.createReadStream(snapshotPath);
stream.on("open", () => stream.pipe(body));
stream.on("error", (err) => body.end(err));
stream.on("end", () => body.end());
return new Response(body as any, {
status: 200,
headers: {
"Content-Type": "application/octet-stream",
"Content-Disposition": `attachment; filename="${path.basename(snapshotPath)}"`,
"Content-Length": (await fs.promises.stat(snapshotPath)).size.toString(),
},
const s3Client = new S3Client({
region: s3Config.region,
...(s3Config.credentials && { credentials: s3Config.credentials }),
...(s3Config.endpoint && { endpoint: s3Config.endpoint, forcePathStyle: true }),
});
const filename = `${getTaskIdentifier()}-${formatDate(new Date())}.heapsnapshot`;
const s3Key = `snapshots/${filename}`;
logger.info("Taking heap snapshot and streaming to S3", {
bucket: s3Config.bucket,
key: s3Key,
});
try {
const startTime = Date.now();
const snapshotStream = v8.getHeapSnapshot();
const upload = new Upload({
client: s3Client,
params: {
Bucket: s3Config.bucket,
Key: s3Key,
Body: snapshotStream,
ContentType: "application/octet-stream",
},
queueSize: QUEUE_SIZE,
partSize: PART_SIZE,
leavePartsOnError: false,
});
let totalBytes = 0;
upload.on("httpUploadProgress", (progress) => {
totalBytes = progress.loaded ?? totalBytes;
logger.info("Upload progress", {
loaded: progress.loaded,
part: progress.part,
});
});
await upload.done();
const duration = Date.now() - startTime;
logger.info("Heap snapshot uploaded to S3", {
bucket: s3Config.bucket,
key: s3Key,
durationMs: duration,
durationSec: Math.round(duration / 1000),
totalBytes,
uploadSpeedMBps: totalBytes > 0 ? Math.round((totalBytes / 1024 / 1024 / (duration / 1000)) * 10) / 10 : 0,
});
return new Response(
JSON.stringify({
success: true,
bucket: s3Config.bucket,
key: s3Key,
sizeBytes: totalBytes,
durationMs: duration,
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
} catch (error) {
logger.error("Failed to upload heap snapshot to S3", {
error: error instanceof Error ? error.message : String(error),
bucket: s3Config.bucket,
key: s3Key,
});
throw new Response(
`Failed to upload snapshot to S3: ${error instanceof Error ? error.message : String(error)}`,
{ status: 500 }
);
}
}
function getTaskIdentifier() {
+1
View File
@@ -31,6 +31,7 @@
"@ariakit/react-core": "^0.4.6",
"@aws-sdk/client-ecr": "^3.931.0",
"@aws-sdk/client-s3": "^3.936.0",
"@aws-sdk/lib-storage": "^3.936.0",
"@aws-sdk/client-sqs": "^3.445.0",
"@aws-sdk/client-sts": "^3.840.0",
"@aws-sdk/credential-provider-node": "^3.936.0",
+38
View File
@@ -8,6 +8,7 @@ volumes:
clickhouse-logs:
prometheus-data:
grafana-data:
minio-data:
networks:
app_network:
@@ -214,3 +215,40 @@ services:
- app_network
depends_on:
- prometheus
minio:
container_name: minio
image: minio/minio:latest
restart: always
volumes:
- minio-data:/data
ports:
- "9002:9000"
- "9003:9001"
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: adminpassword
networks:
- app_network
command: server /data --console-address ":9001"
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 5
minio-setup:
container_name: minio-setup
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
networks:
- app_network
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 admin adminpassword;
mc mb --ignore-existing local/snapshots;
mc mb --ignore-existing local/packets;
exit 0;
"
+239 -6
View File
@@ -232,6 +232,9 @@ importers:
'@aws-sdk/credential-provider-node':
specifier: ^3.936.0
version: 3.940.0
'@aws-sdk/lib-storage':
specifier: ^3.936.0
version: 3.975.0(@aws-sdk/client-s3@3.940.0)
'@aws-sdk/s3-presigned-post':
specifier: ^3.936.0
version: 3.940.0
@@ -1088,7 +1091,7 @@ importers:
version: 18.3.1
react-email:
specifier: ^2.1.1
version: 2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(bufferutil@4.0.9)(eslint@8.31.0)
version: 2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(eslint@8.31.0)
resend:
specifier: ^3.2.0
version: 3.2.0
@@ -3281,6 +3284,12 @@ packages:
resolution: {integrity: sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==}
engines: {node: '>=18.0.0'}
'@aws-sdk/lib-storage@3.975.0':
resolution: {integrity: sha512-F6vrnZ3F7oqr3oONCIpx+uZDTwXWfh8sBoNNJollDn5pIn7TI+R+7WxVIXAMq/JWLXE6N8T3M6ogWk4Y4JWPPw==}
engines: {node: '>=20.0.0'}
peerDependencies:
'@aws-sdk/client-s3': 3.975.0
'@aws-sdk/middleware-bucket-endpoint@3.936.0':
resolution: {integrity: sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==}
engines: {node: '>=18.0.0'}
@@ -9402,6 +9411,10 @@ packages:
resolution: {integrity: sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==}
engines: {node: '>=18.0.0'}
'@smithy/abort-controller@4.2.8':
resolution: {integrity: sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==}
engines: {node: '>=18.0.0'}
'@smithy/chunked-blob-reader-native@4.2.1':
resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==}
engines: {node: '>=18.0.0'}
@@ -9431,6 +9444,10 @@ packages:
resolution: {integrity: sha512-6gnIz3h+PEPQGDj8MnRSjDvKBah042jEoPgjFGJ4iJLBE78L4lY/n98x14XyPF4u3lN179Ub/ZKFY5za9GeLQw==}
engines: {node: '>=18.0.0'}
'@smithy/core@3.21.1':
resolution: {integrity: sha512-NUH8R4O6FkN8HKMojzbGg/5pNjsfTjlMmeFclyPfPaXXUrbr5TzhWgbf7t92wfrpCHRgpjyz7ffASIS3wX28aA==}
engines: {node: '>=18.0.0'}
'@smithy/core@3.6.0':
resolution: {integrity: sha512-Pgvfb+TQ4wUNLyHzvgCP4aYZMh16y7GcfF59oirRHcgGgkH1e/s9C0nv/v3WP+Quymyr5je71HeFQCwh+44XLg==}
engines: {node: '>=18.0.0'}
@@ -9481,6 +9498,10 @@ packages:
resolution: {integrity: sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==}
engines: {node: '>=18.0.0'}
'@smithy/fetch-http-handler@5.3.9':
resolution: {integrity: sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==}
engines: {node: '>=18.0.0'}
'@smithy/hash-blob-browser@4.2.6':
resolution: {integrity: sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==}
engines: {node: '>=18.0.0'}
@@ -9555,6 +9576,10 @@ packages:
resolution: {integrity: sha512-9pAX/H+VQPzNbouhDhkW723igBMLgrI8OtX+++M7iKJgg/zY/Ig3i1e6seCcx22FWhE6Q/S61BRdi2wXBORT+A==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-endpoint@4.4.11':
resolution: {integrity: sha512-/WqsrycweGGfb9sSzME4CrsuayjJF6BueBmkKlcbeU5q18OhxRrvvKlmfw3tpDsK5ilx2XUJvoukwxHB0nHs/Q==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-retry@2.0.21':
resolution: {integrity: sha512-EZS1EXv1k6IJX6hyu/0yNQuPcPaXwG8SWljQHYueyRbOxmqYgoWMWPtfZj0xRRQ4YtLawQSpBgAeiJltq8/MPw==}
engines: {node: '>=14.0.0'}
@@ -9587,6 +9612,10 @@ packages:
resolution: {integrity: sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-serde@4.2.9':
resolution: {integrity: sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-stack@2.0.8':
resolution: {integrity: sha512-7/N59j0zWqVEKExJcA14MrLDZ/IeN+d6nbkN8ucs+eURyaDUXWYlZrQmMOd/TyptcQv0+RDlgag/zSTTV62y/Q==}
engines: {node: '>=14.0.0'}
@@ -9599,6 +9628,10 @@ packages:
resolution: {integrity: sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==}
engines: {node: '>=18.0.0'}
'@smithy/middleware-stack@4.2.8':
resolution: {integrity: sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==}
engines: {node: '>=18.0.0'}
'@smithy/node-config-provider@2.1.6':
resolution: {integrity: sha512-HLqTs6O78m3M3z1cPLFxddxhEPv5MkVatfPuxoVO3A+cHZanNd/H5I6btcdHy6N2CB1MJ/lihJC92h30SESsBA==}
engines: {node: '>=14.0.0'}
@@ -9611,6 +9644,10 @@ packages:
resolution: {integrity: sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==}
engines: {node: '>=18.0.0'}
'@smithy/node-config-provider@4.3.8':
resolution: {integrity: sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==}
engines: {node: '>=18.0.0'}
'@smithy/node-http-handler@2.1.10':
resolution: {integrity: sha512-lkALAwtN6odygIM4nB8aHDahINM6WXXjNrZmWQAh0RSossySRT2qa31cFv0ZBuAYVWeprskRk13AFvvLmf1WLw==}
engines: {node: '>=14.0.0'}
@@ -9623,6 +9660,10 @@ packages:
resolution: {integrity: sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==}
engines: {node: '>=18.0.0'}
'@smithy/node-http-handler@4.4.8':
resolution: {integrity: sha512-q9u+MSbJVIJ1QmJ4+1u+cERXkrhuILCBDsJUBAW1MPE6sFonbCNaegFuwW9ll8kh5UdyY3jOkoOGlc7BesoLpg==}
engines: {node: '>=18.0.0'}
'@smithy/property-provider@2.0.15':
resolution: {integrity: sha512-YbRFBn8oiiC3o1Kn3a4KjGa6k47rCM9++5W9cWqYn9WnkyH+hBWgfJAckuxpyA2Hq6Ys4eFrWzXq6fqHEw7iew==}
engines: {node: '>=14.0.0'}
@@ -9635,6 +9676,10 @@ packages:
resolution: {integrity: sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==}
engines: {node: '>=18.0.0'}
'@smithy/property-provider@4.2.8':
resolution: {integrity: sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==}
engines: {node: '>=18.0.0'}
'@smithy/protocol-http@3.0.10':
resolution: {integrity: sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==}
engines: {node: '>=14.0.0'}
@@ -9647,6 +9692,10 @@ packages:
resolution: {integrity: sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==}
engines: {node: '>=18.0.0'}
'@smithy/protocol-http@5.3.8':
resolution: {integrity: sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==}
engines: {node: '>=18.0.0'}
'@smithy/querystring-builder@2.0.14':
resolution: {integrity: sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==}
engines: {node: '>=14.0.0'}
@@ -9659,6 +9708,10 @@ packages:
resolution: {integrity: sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==}
engines: {node: '>=18.0.0'}
'@smithy/querystring-builder@4.2.8':
resolution: {integrity: sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==}
engines: {node: '>=18.0.0'}
'@smithy/querystring-parser@2.0.14':
resolution: {integrity: sha512-+cbtXWI9tNtQjlgQg3CA+pvL3zKTAxPnG3Pj6MP89CR3vi3QMmD0SOWoq84tqZDnJCxlsusbgIXk1ngMReXo+A==}
engines: {node: '>=14.0.0'}
@@ -9671,6 +9724,10 @@ packages:
resolution: {integrity: sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==}
engines: {node: '>=18.0.0'}
'@smithy/querystring-parser@4.2.8':
resolution: {integrity: sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==}
engines: {node: '>=18.0.0'}
'@smithy/service-error-classification@2.0.7':
resolution: {integrity: sha512-LLxgW12qGz8doYto15kZ4x1rHjtXl0BnCG6T6Wb8z2DI4PT9cJfOSvzbuLzy7+5I24PAepKgFeWHRd9GYy3Z9w==}
engines: {node: '>=14.0.0'}
@@ -9695,6 +9752,10 @@ packages:
resolution: {integrity: sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==}
engines: {node: '>=18.0.0'}
'@smithy/shared-ini-file-loader@4.4.3':
resolution: {integrity: sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==}
engines: {node: '>=18.0.0'}
'@smithy/signature-v4@2.0.16':
resolution: {integrity: sha512-ilLY85xS2kZZzTb83diQKYLIYALvart0KnBaKnIRnMBHAGEio5aHSlANQoxVn0VsonwmQ3CnWhnCT0sERD8uTg==}
engines: {node: '>=14.0.0'}
@@ -9711,6 +9772,10 @@ packages:
resolution: {integrity: sha512-Lw67+yQSpLl4YkDLUzI2KgS8TXclXmbzSeOJUmRFS4ueT56B4pw3RZRF/SRzvgyxM/HxgkUan8oSHXCujPDafQ==}
engines: {node: '>=14.0.0'}
'@smithy/smithy-client@4.10.12':
resolution: {integrity: sha512-VKO/HKoQ5OrSHW6AJUmEnUKeXI1/5LfCwO9cwyao7CmLvGnZeM1i36Lyful3LK1XU7HwTVieTqO1y2C/6t3qtA==}
engines: {node: '>=18.0.0'}
'@smithy/smithy-client@4.4.5':
resolution: {integrity: sha512-+lynZjGuUFJaMdDYSTMnP/uPBBXXukVfrJlP+1U/Dp5SFTEI++w6NMga8DjOENxecOF71V9Z2DllaVDYRnGlkg==}
engines: {node: '>=18.0.0'}
@@ -9727,6 +9792,10 @@ packages:
resolution: {integrity: sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==}
engines: {node: '>=14.0.0'}
'@smithy/types@4.12.0':
resolution: {integrity: sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==}
engines: {node: '>=18.0.0'}
'@smithy/types@4.3.1':
resolution: {integrity: sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==}
engines: {node: '>=18.0.0'}
@@ -9746,6 +9815,10 @@ packages:
resolution: {integrity: sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==}
engines: {node: '>=18.0.0'}
'@smithy/url-parser@4.2.8':
resolution: {integrity: sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==}
engines: {node: '>=18.0.0'}
'@smithy/util-base64@2.0.1':
resolution: {integrity: sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==}
engines: {node: '>=14.0.0'}
@@ -9873,6 +9946,10 @@ packages:
resolution: {integrity: sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==}
engines: {node: '>=18.0.0'}
'@smithy/util-middleware@4.2.8':
resolution: {integrity: sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==}
engines: {node: '>=18.0.0'}
'@smithy/util-retry@2.0.7':
resolution: {integrity: sha512-fIe5yARaF0+xVT1XKcrdnHKTJ1Vc4+3e3tLDjCuIcE9b6fkBzzGFY7AFiX4M+vj6yM98DrwkuZeHf7/hmtVp0Q==}
engines: {node: '>= 14.0.0'}
@@ -9893,6 +9970,10 @@ packages:
resolution: {integrity: sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==}
engines: {node: '>=18.0.0'}
'@smithy/util-stream@4.5.10':
resolution: {integrity: sha512-jbqemy51UFSZSp2y0ZmRfckmrzuKww95zT9BYMmuJ8v3altGcqjwoV1tzpOwuHaKrwQrCjIzOib499ymr2f98g==}
engines: {node: '>=18.0.0'}
'@smithy/util-stream@4.5.6':
resolution: {integrity: sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==}
engines: {node: '>=18.0.0'}
@@ -11697,6 +11778,9 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
buffer@5.6.0:
resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==}
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
@@ -18329,6 +18413,9 @@ packages:
std-env@3.9.0:
resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
stream-browserify@3.0.0:
resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
stream-buffers@3.0.2:
resolution: {integrity: sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==}
engines: {node: '>= 0.10.0'}
@@ -21293,6 +21380,17 @@ snapshots:
transitivePeerDependencies:
- aws-crt
'@aws-sdk/lib-storage@3.975.0(@aws-sdk/client-s3@3.940.0)':
dependencies:
'@aws-sdk/client-s3': 3.940.0
'@smithy/abort-controller': 4.2.8
'@smithy/middleware-endpoint': 4.4.11
'@smithy/smithy-client': 4.10.12
buffer: 5.6.0
events: 3.3.0
stream-browserify: 3.0.0
tslib: 2.8.1
'@aws-sdk/middleware-bucket-endpoint@3.936.0':
dependencies:
'@aws-sdk/types': 3.936.0
@@ -29039,6 +29137,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/abort-controller@4.2.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/chunked-blob-reader-native@4.2.1':
dependencies:
'@smithy/util-base64': 4.3.0
@@ -29099,6 +29202,19 @@ snapshots:
'@smithy/uuid': 1.1.0
tslib: 2.8.1
'@smithy/core@3.21.1':
dependencies:
'@smithy/middleware-serde': 4.2.9
'@smithy/protocol-http': 5.3.8
'@smithy/types': 4.12.0
'@smithy/util-base64': 4.3.0
'@smithy/util-body-length-browser': 4.2.0
'@smithy/util-middleware': 4.2.8
'@smithy/util-stream': 4.5.10
'@smithy/util-utf8': 4.2.0
'@smithy/uuid': 1.1.0
tslib: 2.8.1
'@smithy/core@3.6.0':
dependencies:
'@smithy/middleware-serde': 4.0.8
@@ -29196,6 +29312,14 @@ snapshots:
'@smithy/util-base64': 4.3.0
tslib: 2.8.1
'@smithy/fetch-http-handler@5.3.9':
dependencies:
'@smithy/protocol-http': 5.3.8
'@smithy/querystring-builder': 4.2.8
'@smithy/types': 4.12.0
'@smithy/util-base64': 4.3.0
tslib: 2.8.1
'@smithy/hash-blob-browser@4.2.6':
dependencies:
'@smithy/chunked-blob-reader': 5.2.0
@@ -29326,6 +29450,17 @@ snapshots:
'@smithy/util-middleware': 4.2.5
tslib: 2.8.1
'@smithy/middleware-endpoint@4.4.11':
dependencies:
'@smithy/core': 3.21.1
'@smithy/middleware-serde': 4.2.9
'@smithy/node-config-provider': 4.3.8
'@smithy/shared-ini-file-loader': 4.4.3
'@smithy/types': 4.12.0
'@smithy/url-parser': 4.2.8
'@smithy/util-middleware': 4.2.8
tslib: 2.8.1
'@smithy/middleware-retry@2.0.21':
dependencies:
'@smithy/node-config-provider': 2.1.6
@@ -29396,6 +29531,12 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/middleware-serde@4.2.9':
dependencies:
'@smithy/protocol-http': 5.3.8
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/middleware-stack@2.0.8':
dependencies:
'@smithy/types': 2.6.0
@@ -29411,6 +29552,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/middleware-stack@4.2.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/node-config-provider@2.1.6':
dependencies:
'@smithy/property-provider': 2.0.15
@@ -29432,6 +29578,13 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/node-config-provider@4.3.8':
dependencies:
'@smithy/property-provider': 4.2.8
'@smithy/shared-ini-file-loader': 4.4.3
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/node-http-handler@2.1.10':
dependencies:
'@smithy/abort-controller': 2.0.14
@@ -29456,6 +29609,14 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/node-http-handler@4.4.8':
dependencies:
'@smithy/abort-controller': 4.2.8
'@smithy/protocol-http': 5.3.8
'@smithy/querystring-builder': 4.2.8
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/property-provider@2.0.15':
dependencies:
'@smithy/types': 2.6.0
@@ -29471,6 +29632,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/property-provider@4.2.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/protocol-http@3.0.10':
dependencies:
'@smithy/types': 2.6.0
@@ -29486,6 +29652,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/protocol-http@5.3.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/querystring-builder@2.0.14':
dependencies:
'@smithy/types': 2.6.0
@@ -29504,6 +29675,12 @@ snapshots:
'@smithy/util-uri-escape': 4.2.0
tslib: 2.8.1
'@smithy/querystring-builder@4.2.8':
dependencies:
'@smithy/types': 4.12.0
'@smithy/util-uri-escape': 4.2.0
tslib: 2.8.1
'@smithy/querystring-parser@2.0.14':
dependencies:
'@smithy/types': 2.6.0
@@ -29519,6 +29696,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/querystring-parser@4.2.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/service-error-classification@2.0.7':
dependencies:
'@smithy/types': 2.6.0
@@ -29546,6 +29728,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/shared-ini-file-loader@4.4.3':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/signature-v4@2.0.16':
dependencies:
'@smithy/eventstream-codec': 2.0.14
@@ -29586,6 +29773,16 @@ snapshots:
'@smithy/util-stream': 2.0.21
tslib: 2.8.1
'@smithy/smithy-client@4.10.12':
dependencies:
'@smithy/core': 3.21.1
'@smithy/middleware-endpoint': 4.4.11
'@smithy/middleware-stack': 4.2.8
'@smithy/protocol-http': 5.3.8
'@smithy/types': 4.12.0
'@smithy/util-stream': 4.5.10
tslib: 2.8.1
'@smithy/smithy-client@4.4.5':
dependencies:
'@smithy/core': 3.6.0
@@ -29620,6 +29817,10 @@ snapshots:
dependencies:
tslib: 2.8.1
'@smithy/types@4.12.0':
dependencies:
tslib: 2.8.1
'@smithy/types@4.3.1':
dependencies:
tslib: 2.8.1
@@ -29646,6 +29847,12 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/url-parser@4.2.8':
dependencies:
'@smithy/querystring-parser': 4.2.8
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/util-base64@2.0.1':
dependencies:
'@smithy/util-buffer-from': 2.0.0
@@ -29830,6 +30037,11 @@ snapshots:
'@smithy/types': 4.9.0
tslib: 2.8.1
'@smithy/util-middleware@4.2.8':
dependencies:
'@smithy/types': 4.12.0
tslib: 2.8.1
'@smithy/util-retry@2.0.7':
dependencies:
'@smithy/service-error-classification': 2.0.7
@@ -29870,6 +30082,17 @@ snapshots:
'@smithy/util-utf8': 4.2.0
tslib: 2.8.1
'@smithy/util-stream@4.5.10':
dependencies:
'@smithy/fetch-http-handler': 5.3.9
'@smithy/node-http-handler': 4.4.8
'@smithy/types': 4.12.0
'@smithy/util-base64': 4.3.0
'@smithy/util-buffer-from': 4.2.0
'@smithy/util-hex-encoding': 4.2.0
'@smithy/util-utf8': 4.2.0
tslib: 2.8.1
'@smithy/util-stream@4.5.6':
dependencies:
'@smithy/fetch-http-handler': 5.3.6
@@ -31963,6 +32186,11 @@ snapshots:
buffer-from@1.1.2: {}
buffer@5.6.0:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
@@ -38600,7 +38828,7 @@ snapshots:
react: 19.1.0
scheduler: 0.26.0
react-email@2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(bufferutil@4.0.9)(eslint@8.31.0):
react-email@2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(eslint@8.31.0):
dependencies:
'@babel/parser': 7.24.1
'@radix-ui/colors': 1.0.1
@@ -38637,8 +38865,8 @@ snapshots:
react: 18.3.1
react-dom: 18.2.0(react@18.3.1)
shelljs: 0.8.5
socket.io: 4.7.3(bufferutil@4.0.9)
socket.io-client: 4.7.3(bufferutil@4.0.9)
socket.io: 4.7.3
socket.io-client: 4.7.3
sonner: 1.3.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1)
source-map-js: 1.0.2
stacktrace-parser: 0.1.10
@@ -39785,7 +40013,7 @@ snapshots:
- supports-color
- utf-8-validate
socket.io-client@4.7.3(bufferutil@4.0.9):
socket.io-client@4.7.3:
dependencies:
'@socket.io/component-emitter': 3.1.0
debug: 4.3.7(supports-color@10.0.0)
@@ -39814,7 +40042,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
socket.io@4.7.3(bufferutil@4.0.9):
socket.io@4.7.3:
dependencies:
accepts: 1.3.8
base64id: 2.0.0
@@ -39995,6 +40223,11 @@ snapshots:
std-env@3.9.0: {}
stream-browserify@3.0.0:
dependencies:
inherits: 2.0.4
readable-stream: 3.6.2
stream-buffers@3.0.2: {}
stream-shift@1.0.3: {}