mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: universal upload
Implementation of a universal upload allowing for multiple storage backends starting with `database` and `s3`. Allows clients to put and retrieve files from either client or server using a blend of client and server actions.
This commit is contained in:
104
packages/lib/universal/upload/server-actions.ts
Normal file
104
packages/lib/universal/upload/server-actions.ts
Normal file
@ -0,0 +1,104 @@
|
||||
'use server';
|
||||
|
||||
import {
|
||||
DeleteObjectCommand,
|
||||
GetObjectCommand,
|
||||
PutObjectCommand,
|
||||
S3Client,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import slugify from '@sindresorhus/slugify';
|
||||
import path from 'node:path';
|
||||
|
||||
import { ONE_HOUR, ONE_SECOND } from '../../constants/time';
|
||||
import { getServerComponentSession } from '../../next-auth/get-server-session';
|
||||
import { alphaid } from '../id';
|
||||
|
||||
export const getPresignPostUrl = async (fileName: string, contentType: string) => {
|
||||
const client = getS3Client();
|
||||
|
||||
const user = await getServerComponentSession();
|
||||
|
||||
// Get the basename and extension for the file
|
||||
const { name, ext } = path.parse(fileName);
|
||||
|
||||
let key = `${alphaid(12)}/${slugify(name)}${ext}`;
|
||||
|
||||
if (user) {
|
||||
key = `${user.id}/${key}`;
|
||||
}
|
||||
|
||||
const putObjectCommand = new PutObjectCommand({
|
||||
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
||||
Key: key,
|
||||
ContentType: contentType,
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(client, putObjectCommand, {
|
||||
expiresIn: ONE_HOUR / ONE_SECOND,
|
||||
});
|
||||
|
||||
return { key, url };
|
||||
};
|
||||
|
||||
export const getAbsolutePresignPostUrl = async (key: string) => {
|
||||
const client = getS3Client();
|
||||
|
||||
const putObjectCommand = new PutObjectCommand({
|
||||
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
||||
Key: key,
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(client, putObjectCommand, {
|
||||
expiresIn: ONE_HOUR / ONE_SECOND,
|
||||
});
|
||||
|
||||
return { key, url };
|
||||
};
|
||||
|
||||
export const getPresignGetUrl = async (key: string) => {
|
||||
const client = getS3Client();
|
||||
|
||||
const getObjectCommand = new GetObjectCommand({
|
||||
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
||||
Key: key,
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(client, getObjectCommand, {
|
||||
expiresIn: ONE_HOUR / ONE_SECOND,
|
||||
});
|
||||
|
||||
return { key, url };
|
||||
};
|
||||
|
||||
export const deleteS3File = async (key: string) => {
|
||||
const client = getS3Client();
|
||||
|
||||
await client.send(
|
||||
new DeleteObjectCommand({
|
||||
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
||||
Key: key,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const getS3Client = () => {
|
||||
if (process.env.NEXT_PUBLIC_UPLOAD_TRANSPORT !== 's3') {
|
||||
throw new Error('Invalid upload transport');
|
||||
}
|
||||
|
||||
const hasCredentials =
|
||||
process.env.NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID &&
|
||||
process.env.NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY;
|
||||
|
||||
return new S3Client({
|
||||
endpoint: process.env.NEXT_PRIVATE_UPLOAD_ENDPOINT || undefined,
|
||||
region: process.env.NEXT_PRIVATE_UPLOAD_REGION || 'us-east-1',
|
||||
credentials: hasCredentials
|
||||
? {
|
||||
accessKeyId: String(process.env.NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID),
|
||||
secretAccessKey: String(process.env.NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY),
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user