Prepare production and Coolify deployment with original exports and datetime pickers
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { HeadBucketCommand, PutBucketCorsCommand, PutBucketLifecycleConfigurationCommand, S3Client } from "@aws-sdk/client-s3";
|
||||
|
||||
// Explicit deployment-only initialization, never run implicitly by web requests.
|
||||
const origin = new URL(process.env.NEXT_PUBLIC_APP_URL!).origin;
|
||||
if (!origin.startsWith("https://")) throw new Error("Storage CORS requires an HTTPS app origin");
|
||||
const bucket = process.env.S3_BUCKET!;
|
||||
if (!bucket || !process.env.S3_ACCESS_KEY || !process.env.S3_SECRET_KEY) throw new Error("Missing storage configuration");
|
||||
const client = new S3Client({
|
||||
endpoint: process.env.S3_ENDPOINT,
|
||||
region: process.env.S3_REGION,
|
||||
forcePathStyle: true,
|
||||
credentials: { accessKeyId: process.env.S3_ACCESS_KEY, secretAccessKey: process.env.S3_SECRET_KEY },
|
||||
requestChecksumCalculation: "WHEN_REQUIRED",
|
||||
});
|
||||
await client.send(new HeadBucketCommand({ Bucket: bucket }));
|
||||
await client.send(new PutBucketCorsCommand({ Bucket: bucket, CORSConfiguration: { CORSRules: [{
|
||||
AllowedOrigins: [origin], AllowedMethods: ["GET", "PUT", "HEAD"], AllowedHeaders: ["*"],
|
||||
ExposeHeaders: ["ETag", "Content-Length"], MaxAgeSeconds: 3600,
|
||||
}] } }));
|
||||
await client.send(new PutBucketLifecycleConfigurationCommand({ Bucket: bucket, LifecycleConfiguration: { Rules: [
|
||||
{ ID: "expire-exports", Status: "Enabled", Filter: { Prefix: "exports/" }, Expiration: { Days: 1 } },
|
||||
{ ID: "abort-incomplete", Status: "Enabled", Filter: { Prefix: "" }, AbortIncompleteMultipartUpload: { DaysAfterInitiation: 1 } },
|
||||
] } }));
|
||||
console.log("Storage CORS and lifecycle configured.");
|
||||
@@ -2,6 +2,9 @@ export {
|
||||
createPresignedGetUrl,
|
||||
createPresignedPutUrl,
|
||||
deletePrefix,
|
||||
deleteObject,
|
||||
getSigningClient,
|
||||
storageConfig,
|
||||
ensureBucket,
|
||||
getObjectBuffer,
|
||||
headObject,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
CreateBucketCommand,
|
||||
DeleteObjectsCommand,
|
||||
DeleteObjectCommand,
|
||||
GetObjectCommand,
|
||||
HeadBucketCommand,
|
||||
HeadObjectCommand,
|
||||
@@ -67,6 +68,11 @@ export async function ensureBucket() {
|
||||
if (bucketReady) return;
|
||||
const client = getSigningClient();
|
||||
const { bucket } = storageConfig();
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
await client.send(new HeadBucketCommand({ Bucket: bucket }));
|
||||
bucketReady = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await client.send(new HeadBucketCommand({ Bucket: bucket }));
|
||||
} catch {
|
||||
@@ -112,7 +118,7 @@ export async function createPresignedPutUrl(input: {
|
||||
);
|
||||
}
|
||||
|
||||
export async function createPresignedGetUrl(key: string) {
|
||||
export async function createPresignedGetUrl(key: string, expiresIn = PRESIGN_GET_SECONDS) {
|
||||
await ensureBucket();
|
||||
const { bucket } = storageConfig();
|
||||
return getSignedUrl(
|
||||
@@ -121,10 +127,14 @@ export async function createPresignedGetUrl(key: string) {
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
}),
|
||||
{ expiresIn: PRESIGN_GET_SECONDS },
|
||||
{ expiresIn },
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteObject(key: string) {
|
||||
await getSigningClient().send(new DeleteObjectCommand({ Bucket: storageConfig().bucket, Key: key }));
|
||||
}
|
||||
|
||||
export async function headObject(
|
||||
key: string,
|
||||
): Promise<HeadObjectCommandOutput | null> {
|
||||
|
||||
Reference in New Issue
Block a user