File size: 2,915 Bytes
cd2a4c2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | // Preconfigured storage helpers for Manus WebDev templates
// Uses the Biz-provided storage proxy (Authorization: Bearer <token>)
import { ENV } from "./_core/env";
type StorageConfig = { baseUrl: string; apiKey: string };
function getStorageConfig(): StorageConfig {
const baseUrl = ENV.forgeApiUrl;
const apiKey = ENV.forgeApiKey;
if (!baseUrl || !apiKey) {
throw new Error(
"Storage proxy credentials missing: set BUILT_IN_FORGE_API_URL and BUILT_IN_FORGE_API_KEY",
);
}
return { baseUrl: baseUrl.replace(/\/+$/, ""), apiKey };
}
function buildUploadUrl(baseUrl: string, relKey: string): URL {
const url = new URL("v1/storage/upload", ensureTrailingSlash(baseUrl));
url.searchParams.set("path", normalizeKey(relKey));
return url;
}
async function buildDownloadUrl(baseUrl: string, relKey: string, apiKey: string): Promise<string> {
const downloadApiUrl = new URL("v1/storage/downloadUrl", ensureTrailingSlash(baseUrl));
downloadApiUrl.searchParams.set("path", normalizeKey(relKey));
const response = await fetch(downloadApiUrl, {
method: "GET",
headers: buildAuthHeaders(apiKey),
});
return (await response.json()).url;
}
function ensureTrailingSlash(value: string): string {
return value.endsWith("/") ? value : `${value}/`;
}
function normalizeKey(relKey: string): string {
return relKey.replace(/^\/+/, "");
}
function toFormData(
data: Buffer | Uint8Array | string,
contentType: string,
fileName: string,
): FormData {
const blob =
typeof data === "string"
? new Blob([data], { type: contentType })
: new Blob([data as any], { type: contentType });
const form = new FormData();
form.append("file", blob, fileName || "file");
return form;
}
function buildAuthHeaders(apiKey: string): HeadersInit {
return { Authorization: `Bearer ${apiKey}` };
}
export async function storagePut(
relKey: string,
data: Buffer | Uint8Array | string,
contentType = "application/octet-stream",
): Promise<{ key: string; url: string }> {
const { baseUrl, apiKey } = getStorageConfig();
const key = normalizeKey(relKey);
const uploadUrl = buildUploadUrl(baseUrl, key);
const formData = toFormData(data, contentType, key.split("/").pop() ?? key);
const response = await fetch(uploadUrl, {
method: "POST",
headers: buildAuthHeaders(apiKey),
body: formData,
});
if (!response.ok) {
const message = await response.text().catch(() => response.statusText);
throw new Error(
`Storage upload failed (${response.status} ${response.statusText}): ${message}`,
);
}
const url = (await response.json()).url;
return { key, url };
}
export async function storageGet(relKey: string): Promise<{ key: string; url: string }> {
const { baseUrl, apiKey } = getStorageConfig();
const key = normalizeKey(relKey);
return {
key,
url: await buildDownloadUrl(baseUrl, key, apiKey),
};
}
|