Support runtime environment variables using server components. This will mean docker images can change env vars for runtime as required.
128 lines
3.5 KiB
TypeScript
128 lines
3.5 KiB
TypeScript
'use server';
|
|
|
|
import {
|
|
DeleteObjectCommand,
|
|
GetObjectCommand,
|
|
PutObjectCommand,
|
|
S3Client,
|
|
} from '@aws-sdk/client-s3';
|
|
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';
|
|
import { getRuntimeEnv } from '../runtime-env/get-runtime-env';
|
|
|
|
export const getPresignPostUrl = async (fileName: string, contentType: string) => {
|
|
const client = getS3Client();
|
|
|
|
const { getSignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
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 { getSignedUrl: getS3SignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
const putObjectCommand = new PutObjectCommand({
|
|
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
|
Key: key,
|
|
});
|
|
|
|
const url = await getS3SignedUrl(client, putObjectCommand, {
|
|
expiresIn: ONE_HOUR / ONE_SECOND,
|
|
});
|
|
|
|
return { key, url };
|
|
};
|
|
|
|
export const getPresignGetUrl = async (key: string) => {
|
|
if (process.env.NEXT_PRIVATE_UPLOAD_DISTRIBUTION_DOMAIN) {
|
|
const distributionUrl = new URL(key, `${process.env.NEXT_PRIVATE_UPLOAD_DISTRIBUTION_DOMAIN}`);
|
|
|
|
const { getSignedUrl: getCloudfrontSignedUrl } = await import('@aws-sdk/cloudfront-signer');
|
|
|
|
const url = getCloudfrontSignedUrl({
|
|
url: distributionUrl.toString(),
|
|
keyPairId: `${process.env.NEXT_PRIVATE_UPLOAD_DISTRIBUTION_KEY_ID}`,
|
|
privateKey: `${process.env.NEXT_PRIVATE_UPLOAD_DISTRIBUTION_KEY_CONTENTS}`,
|
|
dateLessThan: new Date(Date.now() + ONE_HOUR).toISOString(),
|
|
});
|
|
|
|
return { key, url };
|
|
}
|
|
|
|
const client = getS3Client();
|
|
|
|
const { getSignedUrl: getS3SignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
const getObjectCommand = new GetObjectCommand({
|
|
Bucket: process.env.NEXT_PRIVATE_UPLOAD_BUCKET,
|
|
Key: key,
|
|
});
|
|
|
|
const url = await getS3SignedUrl(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 = () => {
|
|
const { NEXT_PUBLIC_UPLOAD_TRANSPORT } = getRuntimeEnv();
|
|
|
|
if (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,
|
|
});
|
|
};
|