make s3 optional

This commit is contained in:
Zai Shi 2025-07-30 14:11:36 -07:00
parent 73d90ca283
commit c883965dde
3 changed files with 38 additions and 11 deletions

View File

@ -50,6 +50,14 @@ STACK_DIRECT_DATABASE_CONNECTION_STRING=# enter your direct (unpooled or session
STACK_SVIX_SERVER_URL=# For prod, leave it empty. For local development, use `http://localhost:8113`
STACK_SVIX_API_KEY=# enter the API key for the Svix webhook service here. Use `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk` for local development
# S3
STACK_S3_ENDPOINT=
STACK_S3_REGION=
STACK_S3_ACCESS_KEY_ID=
STACK_S3_SECRET_ACCESS_KEY=
STACK_S3_BUCKET=
# Misc, optional
STACK_ACCESS_TOKEN_EXPIRATION_TIME=# enter the expiration time for the access token here. Optional, don't specify it for default value
STACK_SETUP_ADMIN_GITHUB_ID=# enter the account ID of the admin user here, and after running the seed script they will be able to access the internal project in the Stack dashboard. Optional, don't specify it for default value

View File

@ -1,20 +1,29 @@
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
import { StatusError } from "@stackframe/stack-shared/dist/utils/errors";
import { StackAssertionError, StatusError } from "@stackframe/stack-shared/dist/utils/errors";
import { parseBase64Image } from "./lib/images";
export const s3 = new S3Client({
region: getEnvVariable("STACK_S3_REGION"),
endpoint: getEnvVariable("STACK_S3_ENDPOINT"),
const S3_REGION = getEnvVariable("STACK_S3_REGION", "us-east-1");
const S3_ENDPOINT = getEnvVariable("STACK_S3_ENDPOINT", "");
const S3_BUCKET = getEnvVariable("STACK_S3_BUCKET", "");
const S3_ACCESS_KEY_ID = getEnvVariable("STACK_S3_ACCESS_KEY_ID", "");
const S3_SECRET_ACCESS_KEY = getEnvVariable("STACK_S3_SECRET_ACCESS_KEY", "");
const HAS_S3 = !!S3_BUCKET && !!S3_ACCESS_KEY_ID && !!S3_SECRET_ACCESS_KEY;
if (!HAS_S3) {
console.warn("S3 bucket is not configured. File upload features will not be available.");
}
const s3Client = HAS_S3 ? new S3Client({
region: S3_REGION,
endpoint: S3_ENDPOINT,
forcePathStyle: true,
credentials: {
accessKeyId: getEnvVariable("STACK_S3_ACCESS_KEY_ID"),
secretAccessKey: getEnvVariable("STACK_S3_SECRET_ACCESS_KEY"),
accessKeyId: S3_ACCESS_KEY_ID,
secretAccessKey: S3_SECRET_ACCESS_KEY,
},
});
export const S3_BUCKET = getEnvVariable("STACK_S3_BUCKET");
export const S3_ENDPOINT = getEnvVariable("STACK_S3_ENDPOINT");
}) : undefined;
export function getS3PublicUrl(key: string): string {
return `${S3_ENDPOINT}/${S3_BUCKET}/${key}`;
@ -29,6 +38,10 @@ export async function uploadBase64Image({
maxBytes?: number,
folderName: string,
}) {
if (!s3Client) {
throw new StackAssertionError("S3 is not configured");
}
const { buffer, metadata } = await parseBase64Image(input, { maxBytes });
const key = `${folderName}/${crypto.randomUUID()}.${metadata.format}`;
@ -39,7 +52,7 @@ export async function uploadBase64Image({
Body: buffer,
});
await s3.send(command);
await s3Client.send(command);
return {
key,

View File

@ -32,3 +32,9 @@ STACK_SVIX_API_KEY=
STACK_OPENAI_API_KEY=# enter your openai api key if you want to use the openai related features
STACK_SKIP_SEED_SCRIPT=# true to skip the seed script
STACK_S3_ENDPOINT=
STACK_S3_REGION=
STACK_S3_ACCESS_KEY_ID=
STACK_S3_SECRET_ACCESS_KEY=
STACK_S3_BUCKET=