diff --git a/.gitignore b/.gitignore
index 1ad6528..d2ae1c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,6 @@ vite.config.ts.timestamp-*
# Sqlite
src/lib/server/db/users.db*
+
+# Storage
+minio-storage
diff --git a/bun.lockb b/bun.lockb
index cefd2ef..4f9038e 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index c19a0e8..fe8ea6e 100644
--- a/package.json
+++ b/package.json
@@ -49,12 +49,14 @@
"@sveltejs/adapter-node": "^5.2.12",
"@types/better-sqlite3": "^7.6.12",
"@types/express": "^5.0.0",
+ "@types/minio": "^7.1.1",
"better-auth": "^1.1.16",
"better-sqlite3": "^11.8.1",
"cassandra-driver": "^4.7.2",
"express": "^4.21.2",
"lucide-svelte": "^0.474.0",
"markdown-it-highlightjs": "^4.2.0",
+ "minio": "^8.0.4",
"mode-watcher": "^0.5.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
diff --git a/src/lib/components/forms/updatePFP.svelte b/src/lib/components/forms/updatePFP.svelte
index 7bc9612..ecb0514 100644
--- a/src/lib/components/forms/updatePFP.svelte
+++ b/src/lib/components/forms/updatePFP.svelte
@@ -1,12 +1,26 @@
-
diff --git a/src/lib/functions/generateReadableStream.ts b/src/lib/functions/generateReadableStream.ts
new file mode 100644
index 0000000..6833587
--- /dev/null
+++ b/src/lib/functions/generateReadableStream.ts
@@ -0,0 +1,13 @@
+export async function generateStream(file: File): Promise {
+ try {
+ await fetch(`/api/upload/`, {
+ method: 'POST',
+ body: file,
+ });
+
+ return true;
+ } catch (e) {
+ console.error(`Error sending stream: ${(e as Error).message}`);
+ return false;
+ }
+}
diff --git a/src/lib/server/storage/minio-client.ts b/src/lib/server/storage/minio-client.ts
new file mode 100644
index 0000000..d80c2a7
--- /dev/null
+++ b/src/lib/server/storage/minio-client.ts
@@ -0,0 +1,54 @@
+import * as Minio from 'minio';
+import { Readable } from 'stream';
+import { v4 } from 'uuid';
+
+interface ClientParams {
+ endPoint: string;
+ port: number;
+ accessKey: string;
+ secretKey: string;
+ useSSL: boolean;
+}
+
+class MinioClient {
+ private client: Minio.Client;
+
+ constructor(params: ClientParams) {
+ this.client = new Minio.Client({
+ endPoint: params.endPoint,
+ port: params.port,
+ useSSL: params.useSSL,
+ accessKey: params.accessKey,
+ secretKey: params.secretKey,
+ });
+ }
+
+ async uploadProfile(stream: Readable) {
+ try {
+ const bucket = 'profile-photos';
+ if (await !this.client.bucketExists(bucket)) {
+ await this.client.makeBucket(bucket, 'us-east-1');
+ console.log('Bucket "' + bucket + '" created in "us-east-1".');
+ }
+
+ const upload = await this.client.putObject(bucket, v4(), stream);
+ console.log(upload);
+ } catch (e) {
+ console.error(`Error uploading file: ${(e as Error).message}`);
+ }
+ }
+}
+
+let fsClient: MinioClient | undefined;
+
+if (process.env.BUILDING !== 'true') {
+ fsClient = new MinioClient({
+ endPoint: 'localhost',
+ port: 9000,
+ accessKey: 'minioadmin',
+ secretKey: 'minioadmin',
+ useSSL: false,
+ });
+}
+
+export { fsClient };
diff --git a/src/routes/(server)/api/upload/+server.ts b/src/routes/(server)/api/upload/+server.ts
new file mode 100644
index 0000000..088d2f1
--- /dev/null
+++ b/src/routes/(server)/api/upload/+server.ts
@@ -0,0 +1,3 @@
+export const POST = async () => {
+ return new Response(undefined, { status: 204 });
+};