fix: make direct upload cors script standalone
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-05-27 11:01:21 +08:00
parent e1e53713b5
commit 9c450a3d07

View File

@ -3,13 +3,21 @@ import "dotenv/config";
import {
GetBucketCorsCommand,
PutBucketCorsCommand,
S3Client,
type CORSRule,
} from "@aws-sdk/client-s3";
import { and, eq } from "drizzle-orm";
import {
createS3Client,
resolveS3UploadTarget,
} from "@/lib/storage/service";
import { db } from "@/lib/db";
import { storageConfig } from "@/lib/db/schema";
type S3UploadConfig = {
endpoint: string;
region: string;
bucket: string;
accessKeyId: string;
secretAccessKey: string;
};
const DEFAULT_ORIGINS = [
"https://ai.yydd.ai",
@ -20,6 +28,103 @@ const DEFAULT_ORIGINS = [
"http://localhost:3001",
];
function normalizeEndpoint(endpoint: string): string {
const trimmed = endpoint.trim().replace(/\/+$/, "");
if (!trimmed) return "";
if (/aliyuncs\.com/i.test(trimmed)) {
const withoutProtocol = trimmed.replace(/^https?:\/\//i, "");
return `https://${withoutProtocol}`;
}
return trimmed;
}
function createS3Client(config: S3UploadConfig) {
const normalizedEndpoint = normalizeEndpoint(config.endpoint);
const lowerEndpoint = normalizedEndpoint.toLowerCase();
const isCloudS3 =
lowerEndpoint.includes("aliyuncs.com") ||
lowerEndpoint.includes("amazonaws.com");
return new S3Client({
endpoint: normalizedEndpoint,
region: config.region || "auto",
credentials: {
accessKeyId: config.accessKeyId,
secretAccessKey: config.secretAccessKey,
},
forcePathStyle: !isCloudS3,
});
}
function toS3Config(value: unknown): S3UploadConfig | null {
const raw = value as Record<string, unknown> | null | undefined;
const endpoint = raw?.endpoint ? normalizeEndpoint(String(raw.endpoint)) : "";
const bucket = raw?.bucket ? String(raw.bucket).trim() : "";
const accessKeyId = raw?.accessKeyId ? String(raw.accessKeyId).trim() : "";
const secretAccessKey = raw?.secretAccessKey
? String(raw.secretAccessKey).trim()
: "";
if (
!raw ||
raw.type !== "s3" ||
raw.isEnabled !== true ||
!endpoint ||
!bucket ||
!accessKeyId ||
!secretAccessKey
) {
return null;
}
return {
endpoint,
region: String(raw.region || "auto").trim() || "auto",
bucket,
accessKeyId,
secretAccessKey,
};
}
function readEnvS3Config(): S3UploadConfig | null {
const endpoint = process.env.S3_ENDPOINT
? normalizeEndpoint(process.env.S3_ENDPOINT)
: "";
const bucket = process.env.S3_BUCKET?.trim() || "";
const accessKeyId = process.env.S3_ACCESS_KEY_ID?.trim() || "";
const secretAccessKey = process.env.S3_SECRET_ACCESS_KEY?.trim() || "";
if (!endpoint || !bucket || !accessKeyId || !secretAccessKey) {
return null;
}
return {
endpoint,
region: process.env.S3_REGION?.trim() || "auto",
bucket,
accessKeyId,
secretAccessKey,
};
}
async function resolveS3Config() {
const [defaultConfig] = await db
.select()
.from(storageConfig)
.where(
and(
eq(storageConfig.type, "s3"),
eq(storageConfig.isDefault, true),
eq(storageConfig.isEnabled, true)
)
)
.limit(1);
return toS3Config(defaultConfig) || readEnvS3Config();
}
function readOrigins() {
const raw = process.env.DIRECT_UPLOAD_CORS_ORIGINS || "";
const origins = raw
@ -51,15 +156,14 @@ function isDirectUploadRule(rule: CORSRule, origins: string[]) {
}
async function main() {
const target = await resolveS3UploadTarget();
if (!target) {
const config = await resolveS3Config();
if (!config) {
console.log("[direct-upload-cors] skip: no S3-compatible upload target");
return;
}
const origins = readOrigins();
const client = createS3Client(target.config);
const bucket = target.config.bucket;
const client = createS3Client(config);
const directRule: CORSRule = {
AllowedOrigins: origins,
AllowedMethods: ["GET", "PUT", "POST", "HEAD"],
@ -70,7 +174,9 @@ async function main() {
let existingRules: CORSRule[] = [];
try {
const current = await client.send(new GetBucketCorsCommand({ Bucket: bucket }));
const current = await client.send(
new GetBucketCorsCommand({ Bucket: config.bucket })
);
existingRules = current.CORSRules || [];
} catch (error) {
console.warn(
@ -88,7 +194,7 @@ async function main() {
await client.send(
new PutBucketCorsCommand({
Bucket: bucket,
Bucket: config.bucket,
CORSConfiguration: {
CORSRules: mergedRules,
},
@ -96,7 +202,7 @@ async function main() {
);
console.log("[direct-upload-cors] configured", {
bucket,
bucket: config.bucket,
origins,
ruleCount: mergedRules.length,
});