This updates developer docs and web demos to use backend upload endpoints, adds a client upload helper, and aligns integration tests with the no-direct-MinIO URL flow. Made-with: Cursor
This commit is contained in:
+2
-33
@@ -57,13 +57,6 @@ function kindFromExt(ext) {
|
||||
return ext === "gltf" || ext === "glb" ? "3d" : "image";
|
||||
}
|
||||
|
||||
function isLikelyInternalHostname(hostname) {
|
||||
if (!hostname) return false;
|
||||
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") return true;
|
||||
if (hostname.endsWith(".local") || hostname.endsWith(".internal")) return true;
|
||||
return hostname.includes("minio") || hostname.includes("docker") || hostname.includes("kubernetes");
|
||||
}
|
||||
|
||||
async function sha256Hex(file) {
|
||||
const buffer = await file.arrayBuffer();
|
||||
const digest = await crypto.subtle.digest("SHA-256", buffer);
|
||||
@@ -208,34 +201,10 @@ async function createFeatureAndUpload() {
|
||||
description: assetDescEl.value.trim(),
|
||||
isPublic: true,
|
||||
});
|
||||
const signedUpload = await client.getAssetSignedUploadUrl(created.asset.id, file.type || "application/octet-stream");
|
||||
let signedHost = "";
|
||||
try {
|
||||
signedHost = new URL(signedUpload.url).hostname;
|
||||
} catch {
|
||||
signedHost = "";
|
||||
}
|
||||
if (signedHost && isLikelyInternalHostname(signedHost) && signedHost !== window.location.hostname) {
|
||||
throw new Error(
|
||||
`Upload URL host "${signedHost}" is not browser-reachable from this page. ` +
|
||||
`Configure S3 endpoint/signing host to a public domain (for example s3.tenerife.baby) or proxy uploads through the API.`
|
||||
);
|
||||
}
|
||||
let uploadRes;
|
||||
try {
|
||||
uploadRes = await fetch(signedUpload.url, {
|
||||
method: signedUpload.method || "PUT",
|
||||
headers: file.type ? { "Content-Type": file.type } : undefined,
|
||||
body: file,
|
||||
});
|
||||
await client.uploadAssetBinary(created.asset.id, file, file.type || "application/octet-stream");
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Network error while uploading to signed URL. ` +
|
||||
`Check that object storage endpoint is publicly reachable and CORS allows browser PUT requests.`
|
||||
);
|
||||
}
|
||||
if (!uploadRes.ok) {
|
||||
throw new Error(`Upload failed with status ${uploadRes.status}`);
|
||||
throw new Error(`Upload failed: ${error.message}`);
|
||||
}
|
||||
|
||||
await refreshFeatures();
|
||||
|
||||
+3
-32
@@ -51,13 +51,6 @@ function kindFromExt(ext) {
|
||||
return ext === "gltf" || ext === "glb" ? "3d" : "image";
|
||||
}
|
||||
|
||||
function isLikelyInternalHostname(hostname) {
|
||||
if (!hostname) return false;
|
||||
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1") return true;
|
||||
if (hostname.endsWith(".local") || hostname.endsWith(".internal")) return true;
|
||||
return hostname.includes("minio") || hostname.includes("docker") || hostname.includes("kubernetes");
|
||||
}
|
||||
|
||||
async function sha256Hex(file) {
|
||||
const buffer = await file.arrayBuffer();
|
||||
const digest = await crypto.subtle.digest("SHA-256", buffer);
|
||||
@@ -273,32 +266,10 @@ async function createFeatureAndUpload() {
|
||||
isPublic: true,
|
||||
});
|
||||
|
||||
const signedUpload = await client.getAssetSignedUploadUrl(created.asset.id, file.type || "application/octet-stream");
|
||||
let signedHost = "";
|
||||
try {
|
||||
signedHost = new URL(signedUpload.url).hostname;
|
||||
} catch {
|
||||
signedHost = "";
|
||||
}
|
||||
if (signedHost && isLikelyInternalHostname(signedHost) && signedHost !== window.location.hostname) {
|
||||
throw new Error(
|
||||
`Upload URL host "${signedHost}" is not browser-reachable. ` +
|
||||
`Use a public S3 endpoint host for signed URLs or add an API upload proxy.`
|
||||
);
|
||||
}
|
||||
|
||||
let uploadRes;
|
||||
try {
|
||||
uploadRes = await fetch(signedUpload.url, {
|
||||
method: signedUpload.method || "PUT",
|
||||
headers: file.type ? { "Content-Type": file.type } : undefined,
|
||||
body: file,
|
||||
});
|
||||
} catch {
|
||||
throw new Error("Network error while uploading. Check S3 endpoint reachability and CORS policy.");
|
||||
}
|
||||
if (!uploadRes.ok) {
|
||||
throw new Error(`Upload failed with status ${uploadRes.status}`);
|
||||
await client.uploadAssetBinary(created.asset.id, file, file.type || "application/octet-stream");
|
||||
} catch (error) {
|
||||
throw new Error(`Upload failed: ${error.message}`);
|
||||
}
|
||||
|
||||
await refreshFeatures();
|
||||
|
||||
Reference in New Issue
Block a user