This commit is contained in:
Zai Shi 2025-07-29 14:20:45 -07:00
parent 7c0417d7d9
commit 4e25c869aa
7 changed files with 1323 additions and 53 deletions

View File

@ -1,49 +1,6 @@
NEXT_PUBLIC_STACK_API_URL=http://localhost:8102
NEXT_PUBLIC_STACK_DASHBOARD_URL=http://localhost:8101
STACK_SERVER_SECRET=23-wuNpik0gIW4mruTz25rbIvhuuvZFrLOLtL7J4tyo
STACK_SEED_INTERNAL_PROJECT_SIGN_UP_ENABLED=true
STACK_SEED_INTERNAL_PROJECT_OTP_ENABLED=true
STACK_SEED_INTERNAL_PROJECT_ALLOW_LOCALHOST=true
STACK_SEED_INTERNAL_PROJECT_OAUTH_PROVIDERS=github,spotify,google,microsoft
STACK_SEED_INTERNAL_PROJECT_USER_INTERNAL_ACCESS=true
STACK_SEED_INTERNAL_PROJECT_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
STACK_SEED_INTERNAL_PROJECT_SECRET_SERVER_KEY=this-secret-server-key-is-for-local-development-only
STACK_SEED_INTERNAL_PROJECT_SUPER_SECRET_ADMIN_KEY=this-super-secret-admin-key-is-for-local-development-only
STACK_OAUTH_MOCK_URL=http://localhost:8114
STACK_GITHUB_CLIENT_ID=MOCK
STACK_GITHUB_CLIENT_SECRET=MOCK
STACK_GOOGLE_CLIENT_ID=MOCK
STACK_GOOGLE_CLIENT_SECRET=MOCK
STACK_MICROSOFT_CLIENT_ID=MOCK
STACK_MICROSOFT_CLIENT_SECRET=MOCK
STACK_SPOTIFY_CLIENT_ID=MOCK
STACK_SPOTIFY_CLIENT_SECRET=MOCK
STACK_ALLOW_SHARED_OAUTH_ACCESS_TOKENS=true
STACK_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:5432/stackframe?connection_limit=20
STACK_DIRECT_DATABASE_CONNECTION_STRING=postgres://postgres:PASSWORD-PLACEHOLDER--uqfEC1hmmv@localhost:5432/stackframe?connection_limit=20
STACK_EMAIL_HOST=127.0.0.1
STACK_EMAIL_PORT=2500
STACK_EMAIL_SECURE=false
STACK_EMAIL_USERNAME=does not matter, ignored by Inbucket
STACK_EMAIL_PASSWORD=does not matter, ignored by Inbucket
STACK_EMAIL_SENDER=noreply@example.com
STACK_ACCESS_TOKEN_EXPIRATION_TIME=30s
STACK_SVIX_SERVER_URL=http://localhost:8113
STACK_SVIX_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NTUxNDA2MzksImV4cCI6MTk3MDUwMDYzOSwibmJmIjoxNjU1MTQwNjM5LCJpc3MiOiJzdml4LXNlcnZlciIsInN1YiI6Im9yZ18yM3JiOFlkR3FNVDBxSXpwZ0d3ZFhmSGlyTXUifQ.En8w77ZJWbd0qrMlHHupHUB-4cx17RfzFykseg95SUk
STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS=50
STACK_ENABLE_HARDCODED_PASSKEY_CHALLENGE_FOR_TESTING=yes
STACK_INTEGRATION_CLIENTS_CONFIG=[{"client_id": "neon-local", "client_secret": "neon-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}, {"client_id": "custom-local", "client_secret": "custom-local-secret", "id_token_signed_response_alg": "ES256", "redirect_uris": ["http://localhost:30000/api/v2/identity/authorize", "http://localhost:30000/api/v2/auth/authorize"]}]
CRON_SECRET=mock_cron_secret
STACK_FREESTYLE_API_KEY=mock_stack_freestyle_key
STACK_OPENAI_API_KEY=mock_openai_api_key
# S3 Configuration for local development using s3mock
STACK_S3_ENDPOINT=http://localhost:8120
STACK_S3_REGION=us-east-1
STACK_S3_ACCESS_KEY_ID=s3mockroot
STACK_S3_SECRET_ACCESS_KEY=s3mockroot
STACK_S3_BUCKET=stack-storage

View File

@ -42,6 +42,8 @@
},
"dependencies": {
"@ai-sdk/openai": "^1.3.23",
"@aws-sdk/client-s3": "^3.855.0",
"@aws-sdk/s3-request-presigner": "^3.855.0",
"@next/bundle-analyzer": "15.2.3",
"@node-oauth/oauth2-server": "^5.1.0",
"@opentelemetry/api": "^1.9.0",
@ -77,8 +79,8 @@
"nodemailer": "^6.9.10",
"oidc-provider": "^8.5.1",
"openid-client": "5.6.4",
"postgres": "^3.4.5",
"pg": "^8.16.3",
"postgres": "^3.4.5",
"posthog-node": "^4.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",

View File

@ -0,0 +1,48 @@
import { S3_BUCKET, getS3PublicUrl, s3 } from "@/s3";
import { PutBucketAclCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
try {
// First, make sure the bucket allows public read access
try {
const bucketAclCommand = new PutBucketAclCommand({
Bucket: S3_BUCKET,
ACL: "public-read",
});
await s3.send(bucketAclCommand);
} catch (aclError) {
console.warn("Could not set bucket ACL (this is normal for S3 mock):", aclError);
}
const exampleContent = "Hello, this is a test file stored in S3!";
const fileName = `test-file-${Date.now()}.txt`;
const command = new PutObjectCommand({
Bucket: S3_BUCKET,
Key: fileName,
Body: exampleContent,
ContentType: "text/plain",
ACL: "public-read", // Make the object publicly readable
});
await s3.send(command);
// Generate the public URL for the uploaded file
const publicUrl = getS3PublicUrl(fileName);
return NextResponse.json({
success: true,
message: "File uploaded successfully",
fileName: fileName,
publicUrl: publicUrl,
bucket: S3_BUCKET,
});
} catch (error) {
console.error("Error uploading file to S3:", error);
return NextResponse.json(
{ success: false, error: "Failed to upload file" },
{ status: 500 }
);
}
}

19
apps/backend/src/s3.tsx Normal file
View File

@ -0,0 +1,19 @@
import { S3Client } from "@aws-sdk/client-s3";
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
export const s3 = new S3Client({
region: getEnvVariable("STACK_S3_REGION"),
endpoint: getEnvVariable("STACK_S3_ENDPOINT"),
forcePathStyle: true,
credentials: {
accessKeyId: getEnvVariable("STACK_S3_ACCESS_KEY_ID"),
secretAccessKey: getEnvVariable("STACK_S3_SECRET_ACCESS_KEY"),
},
});
export const S3_BUCKET = getEnvVariable("STACK_S3_BUCKET", "stack-storage");
export const S3_ENDPOINT = getEnvVariable("STACK_S3_ENDPOINT");
export function getS3PublicUrl(key: string): string {
return `${S3_ENDPOINT}/${S3_BUCKET}/${key}`;
}

View File

@ -268,6 +268,17 @@
importance: 1,
img: "https://cdn.prod.website-files.com/655b60964be1a1b36c746790/655b60964be1a1b36c746d41_646dfce3b9c4849f6e401bff_supabase-logo-icon_1.png",
},
{
name: "JS example",
port: 8119,
description: [
"JavaScript example",
],
},
{
name: "S3 Mock",
port: 8120,
},
];
const appsContainers = document.querySelectorAll(".apps-container");

View File

@ -134,6 +134,24 @@ services:
- svix-redis
- svix-db
# ================= Adobe S3 Mock =================
s3mock:
image: adobe/s3mock:latest
ports:
- 8120:9090
environment:
- initialBuckets=stack-storage
- root=s3mockroot
- debug=false
volumes:
- s3mock-data:/tmp/s3mock
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9090/"]
interval: 30s
timeout: 10s
retries: 3
# ================= volumes =================
volumes:
@ -141,7 +159,8 @@ volumes:
inbucket-data:
svix-redis-data:
svix-postgres-data:
s3mock-data:
# ================= configs =================
configs:

File diff suppressed because it is too large Load Diff