mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-04 12:45:17 +02:00
Multi provider
This commit is contained in:
parent
ee32a446e9
commit
a535072224
6 changed files with 1323 additions and 392 deletions
|
@ -38,12 +38,12 @@
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.592.0",
|
||||||
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
||||||
"@vercel/analytics": "^1.2.2",
|
"@vercel/analytics": "^1.2.2",
|
||||||
"@vercel/speed-insights": "^1.0.10",
|
"@vercel/speed-insights": "^1.0.10",
|
||||||
"drizzle-orm": "^0.30.6",
|
"drizzle-orm": "^0.30.6",
|
||||||
"iconify-icon": "^2.1.0",
|
"iconify-icon": "^2.1.0",
|
||||||
"minio": "^8.0.0",
|
|
||||||
"oslo": "^1.2.0",
|
"oslo": "^1.2.0",
|
||||||
"postgres": "^3.4.4"
|
"postgres": "^3.4.4"
|
||||||
}
|
}
|
||||||
|
|
1532
pnpm-lock.yaml
generated
1532
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
||||||
import { Client } from "minio";
|
|
||||||
const MINIO_SERVER_URL = process.env.MINIO_SERVER_URL;
|
|
||||||
const MINIO_ACCESS_KEY = process.env.MINIO_ACCESS_KEY;
|
|
||||||
const MINIO_SECRET_KEY = process.env.MINIO_SECRET_KEY;
|
|
||||||
const MINIO_CLIENT_URL = process.env.MINIO_CLIENT_URL;
|
|
||||||
const MINIO_USE_SSL = process.env.MINIO_USE_SSL;
|
|
||||||
const port = MINIO_CLIENT_URL?.split(":").pop(); // 9000
|
|
||||||
|
|
||||||
const minioClient = new Client({
|
|
||||||
endPoint: MINIO_SERVER_URL ? MINIO_SERVER_URL : "localhost",
|
|
||||||
port: port ? parseInt(port) : 9000,
|
|
||||||
useSSL: MINIO_USE_SSL ? MINIO_USE_SSL === "true" : false,
|
|
||||||
accessKey: MINIO_ACCESS_KEY as string,
|
|
||||||
secretKey: MINIO_SECRET_KEY as string,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default minioClient;
|
|
117
src/lib/server/s3.ts
Normal file
117
src/lib/server/s3.ts
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
import {
|
||||||
|
CreateBucketCommand,
|
||||||
|
HeadBucketCommand,
|
||||||
|
PutBucketPolicyCommand,
|
||||||
|
PutObjectCommand,
|
||||||
|
S3Client,
|
||||||
|
type S3ClientConfig,
|
||||||
|
} from "@aws-sdk/client-s3";
|
||||||
|
import { env } from "$env/dynamic/private";
|
||||||
|
console.log(env.AWS_ACCESS_KEY_ID as string);
|
||||||
|
|
||||||
|
const s3Config: S3ClientConfig = {
|
||||||
|
region: env.AWS_REGION as string,
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: env.AWS_ACCESS_KEY_ID as string,
|
||||||
|
secretAccessKey: env.AWS_SECRET_ACCESS_KEY as string,
|
||||||
|
},
|
||||||
|
endpoint: env.AWS_S3_ENDPOINT, // Add the endpoint
|
||||||
|
forcePathStyle: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const s3Client = new S3Client(s3Config);
|
||||||
|
|
||||||
|
export const ensureBucketExists = async (bucketName: string): Promise<void> => {
|
||||||
|
const headBucketCommand = new HeadBucketCommand({ Bucket: bucketName });
|
||||||
|
|
||||||
|
try {
|
||||||
|
await s3Client.send(headBucketCommand);
|
||||||
|
console.log(`Bucket ${bucketName} already exists.`);
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.$metadata.httpStatusCode === 404) {
|
||||||
|
console.log(`Bucket ${bucketName} does not exist. Creating...`);
|
||||||
|
const createBucketCommand = new CreateBucketCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
});
|
||||||
|
await s3Client.send(createBucketCommand);
|
||||||
|
|
||||||
|
// Set a bucket policy to allow public read access
|
||||||
|
const bucketPolicy = {
|
||||||
|
Version: "2012-10-17",
|
||||||
|
Statement: [
|
||||||
|
{
|
||||||
|
Effect: "Allow",
|
||||||
|
Principal: "*", // This allows anyone (public)
|
||||||
|
Action: ["s3:GetBucketLocation", "s3:ListBucket"],
|
||||||
|
Resource: `arn:aws:s3:::${bucketName}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Effect: "Allow",
|
||||||
|
Principal: "*", // This allows anyone (public)
|
||||||
|
Action: "s3:GetObject",
|
||||||
|
Resource: `arn:aws:s3:::${bucketName}/*`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const putBucketPolicyCommand = new PutBucketPolicyCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
Policy: JSON.stringify(bucketPolicy),
|
||||||
|
});
|
||||||
|
await s3Client.send(putBucketPolicyCommand);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Bucket ${bucketName} created and public read access policy set.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw error; // Rethrow other errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const uploadObject = async (
|
||||||
|
bucketName: string,
|
||||||
|
fileName: string,
|
||||||
|
fileBuffer: Buffer
|
||||||
|
): Promise<string> => {
|
||||||
|
const putObjectCommand = new PutObjectCommand({
|
||||||
|
Bucket: bucketName,
|
||||||
|
Key: fileName,
|
||||||
|
Body: fileBuffer,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await s3Client.send(putObjectCommand);
|
||||||
|
|
||||||
|
// Determine the provider from the endpoint
|
||||||
|
let endpoint = env.AWS_S3_ENDPOINT as string;
|
||||||
|
let objectUrl: string;
|
||||||
|
|
||||||
|
if (endpoint.includes("amazonaws.com")) {
|
||||||
|
// Amazon S3
|
||||||
|
objectUrl = `https://${bucketName}.s3.${env.AWS_REGION}.amazonaws.com/${fileName}`;
|
||||||
|
} else if (endpoint.includes("storage.googleapis.com")) {
|
||||||
|
// Google Cloud Storage
|
||||||
|
objectUrl = `https://storage.googleapis.com/${bucketName}/${fileName}`;
|
||||||
|
} else if (endpoint.includes("digitaloceanspaces.com")) {
|
||||||
|
// DigitalOcean Spaces
|
||||||
|
objectUrl = `https://${bucketName}.${endpoint}/${fileName}`;
|
||||||
|
} else if (endpoint.includes("supabase.co")) {
|
||||||
|
// Supabase Storage
|
||||||
|
endpoint = endpoint.replace("s3", "object/public"); // Remove the version
|
||||||
|
console.log(endpoint);
|
||||||
|
objectUrl = `${endpoint}/${bucketName}/${fileName}`;
|
||||||
|
} else {
|
||||||
|
// Default fallback
|
||||||
|
objectUrl = `${endpoint}/${bucketName}/${fileName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
`Error uploading file ${fileName} to bucket ${bucketName}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,9 +1,9 @@
|
||||||
// src/routes/api/upload.js
|
// src/routes/api/upload.js
|
||||||
|
|
||||||
import minioClient from "$lib/server/minio.js";
|
import { ensureBucketExists, s3Client, uploadObject } from "$lib/server/s3";
|
||||||
|
import { HeadBucketCommand } from "@aws-sdk/client-s3";
|
||||||
import type { RequestEvent } from "@sveltejs/kit";
|
import type { RequestEvent } from "@sveltejs/kit";
|
||||||
import { generateId } from "lucia";
|
import { generateId } from "lucia";
|
||||||
const MINIO_CLIENT_URL = process.env.MINIO_CLIENT_URL;
|
|
||||||
|
|
||||||
export async function POST(event: RequestEvent): Promise<Response> {
|
export async function POST(event: RequestEvent): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
|
@ -35,48 +35,17 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
||||||
"Content-Type": contentType,
|
"Content-Type": contentType,
|
||||||
};
|
};
|
||||||
|
|
||||||
const found: Boolean = await minioClient.bucketExists("profile-pics");
|
await ensureBucketExists("profile-pics");
|
||||||
|
|
||||||
if (!found) {
|
const objectUrl = await uploadObject(
|
||||||
await minioClient.makeBucket("profile-pics");
|
|
||||||
// Set a bucket policy to allow public read access
|
|
||||||
const bucketPolicy = {
|
|
||||||
Version: "2012-10-17",
|
|
||||||
Statement: [
|
|
||||||
{
|
|
||||||
Effect: "Allow",
|
|
||||||
Principal: "*",
|
|
||||||
Action: ["s3:GetBucketLocation", "s3:ListBucket"],
|
|
||||||
Resource: `arn:aws:s3:::profile-pics`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Effect: "Allow",
|
|
||||||
Principal: "*",
|
|
||||||
Action: "s3:GetObject",
|
|
||||||
Resource: `arn:aws:s3:::profile-pics/*`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await minioClient.setBucketPolicy(
|
|
||||||
"profile-pics",
|
|
||||||
JSON.stringify(bucketPolicy)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await minioClient.putObject(
|
|
||||||
"profile-pics",
|
"profile-pics",
|
||||||
fileName,
|
fileName,
|
||||||
Buffer.from(fileBuffer)
|
Buffer.from(fileBuffer)
|
||||||
);
|
);
|
||||||
|
|
||||||
const fileUrl = await minioClient.presignedGetObject(
|
console.log(`File uploaded to ${objectUrl}`);
|
||||||
"profile-pics",
|
|
||||||
fileName
|
|
||||||
);
|
|
||||||
|
|
||||||
const publicUrl = `${MINIO_CLIENT_URL}/profile-pics/${fileName}`;
|
return new Response(JSON.stringify({ objectUrl }), {
|
||||||
|
|
||||||
return new Response(JSON.stringify({ publicUrl }), {
|
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
|
|
@ -82,8 +82,8 @@ export const actions: Actions = {
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log("DATA" + data.publicUrl);
|
console.log("DATA" + data.objectUrl);
|
||||||
icon = data.publicUrl;
|
icon = data.objectUrl;
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
throw error(400, {
|
throw error(400, {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue